Skip to main content

Error Handling

RustMailer implements a comprehensive error handling system that provides consistent, structured error responses across both REST and gRPC APIs. This guide explains how to understand and handle all error scenarios when integrating with RustMailer.

Error Response Structure

All API errors follow a consistent JSON structure:

{
"code": 30000,
"message": "Resource not found"
}
  • code: A unique numeric identifier for the error type
  • message: A human-readable description of the error

Complete Error Code Reference

RustMailer defines 36 error codes organized into 7 logical categories:

Client Errors (10000-10999)

These errors indicate problems with the client request or input validation.

CodeNameHTTP StatusgRPC StatusDescription
10000InvalidParameter400 Bad RequestINVALID_ARGUMENTInvalid request parameters or malformed data
10010VRLScriptSyntaxError400 Bad RequestINVALID_ARGUMENTVRL script contains syntax errors
10020MissingConfiguration400 Bad RequestINVALID_ARGUMENTRequired configuration is missing
10030Incompatible400 Bad RequestINVALID_ARGUMENTIncompatible request or configuration
10040ExceedsLimitation400 Bad RequestINVALID_ARGUMENTRequest exceeds system limitations
10050EmlFileParseError400 Bad RequestINVALID_ARGUMENTEML file parsing failed
10060MissingContentLength411 Length RequiredINVALID_ARGUMENTContent-Length header is missing
10070PayloadTooLarge413 Payload Too LargeRESOURCE_EXHAUSTEDRequest payload exceeds size limits
10080RequestTimeout408 Request TimeoutDEADLINE_EXCEEDEDRequest processing timeout
10090MethodNotAllowed405 Method Not AllowedUNIMPLEMENTEDHTTP method not supported for endpoint

Authentication & Authorization Errors (20000-20999)

These errors relate to authentication, authorization, and access control.

CodeNameHTTP StatusgRPC StatusDescription
20000PermissionDenied401 UnauthorizedPERMISSION_DENIEDAuthentication required or invalid credentials
20010AccountDisabled403 ForbiddenPERMISSION_DENIEDEmail account is disabled
20020LicenseAccountLimitReached403 ForbiddenPERMISSION_DENIEDMaximum licensed accounts exceeded
20030LicenseExpired403 ForbiddenPERMISSION_DENIEDLicense has expired
20040InvalidLicense403 ForbiddenPERMISSION_DENIEDLicense key is invalid
20050OAuth2ItemDisabled403 ForbiddenPERMISSION_DENIEDOAuth2 configuration is disabled
20060MissingRefreshToken500 Internal Server ErrorINTERNALOAuth2 refresh token is missing

Resource Errors (30000-30999)

These errors involve resource management and availability.

CodeNameHTTP StatusgRPC StatusDescription
30000ResourceNotFound404 Not FoundNOT_FOUNDRequested resource does not exist
30010AlreadyExists409 ConflictALREADY_EXISTSResource already exists (duplicate creation)
30020TooManyRequest429 Too Many RequestsRESOURCE_EXHAUSTEDRate limit exceeded

Network & Connection Errors (40000-40999)

These errors relate to network connectivity and communication issues.

CodeNameHTTP StatusgRPC StatusDescription
40000NetworkError500 Internal Server ErrorINTERNALNetwork connectivity issues
40010ConnectionTimeout500 Internal Server ErrorINTERNALConnection timeout to external services
40020ConnectionPoolTimeout500 Internal Server ErrorINTERNALDatabase connection pool timeout
40030HttpResponseError500 Internal Server ErrorINTERNALHTTP response error from external service

Email Service Errors (50000-50999)

These errors are specific to email protocol operations (IMAP/SMTP).

CodeNameHTTP StatusgRPC StatusDescription
50000ImapCommandFailed500 Internal Server ErrorINTERNALIMAP server command failed
50010ImapAuthenticationFailed500 Internal Server ErrorINTERNALIMAP authentication failed
50020ImapUnexpectedResult500 Internal Server ErrorINTERNALIMAP server returned unexpected result
50030SmtpCommandFailed500 Internal Server ErrorINTERNALSMTP server command failed
50040SmtpConnectionFailed500 Internal Server ErrorINTERNALSMTP connection failed
50050MailBoxNotCached500 Internal Server ErrorINTERNALMailbox not cached
50060AutoconfigFetchFailed500 Internal Server ErrorINTERNALFailed to fetch auto-configuration

Message Queue Errors (60000-60999)

These errors relate to NATS message queue operations.

CodeNameHTTP StatusgRPC StatusDescription
60000NatsRequestFailed500 Internal Server ErrorINTERNALNATS request failed
60010NatsConnectionFailed500 Internal Server ErrorINTERNALNATS connection failed
60020NatsCreateStreamFailed500 Internal Server ErrorINTERNALNATS stream creation failed

System Internal Errors (70000-70999)

These are general system-level errors.

CodeNameHTTP StatusgRPC StatusDescription
70000InternalError500 Internal Server ErrorINTERNALGeneral internal server error
70010UnhandledPoemError500 Internal Server ErrorINTERNALUnhandled Poem framework error

Error Handling Best Practices

1. Error Code Range Detection

You can quickly identify error categories by examining the error code range:

function getErrorCategory(errorCode) {
if (errorCode >= 10000 && errorCode < 20000) return 'CLIENT_ERROR';
if (errorCode >= 20000 && errorCode < 30000) return 'AUTH_ERROR';
if (errorCode >= 30000 && errorCode < 40000) return 'RESOURCE_ERROR';
if (errorCode >= 40000 && errorCode < 50000) return 'NETWORK_ERROR';
if (errorCode >= 50000 && errorCode < 60000) return 'EMAIL_SERVICE_ERROR';
if (errorCode >= 60000 && errorCode < 70000) return 'MESSAGE_QUEUE_ERROR';
if (errorCode >= 70000 && errorCode < 80000) return 'SYSTEM_ERROR';
return 'UNKNOWN_ERROR';
}

2. HTTP Status Code Handling

async function handleApiResponse(response) {
if (!response.ok) {
const errorData = await response.json();
const category = getErrorCategory(errorData.code);

switch (category) {
case 'CLIENT_ERROR':
// Handle client-side errors (fix request)
console.error('Client error:', errorData.message);
break;
case 'AUTH_ERROR':
// Handle authentication/authorization errors
redirectToLogin();
break;
case 'RESOURCE_ERROR':
// Handle resource-related errors
handleResourceError(errorData.code);
break;
default:
// Handle server errors with retry logic
scheduleRetry();
break;
}
}
}

3. gRPC Error Handling

For gRPC clients, the original RustMailer error code is available in metadata:

// gRPC client example
try {
const response = await client.someMethod(request);
} catch (error) {
const rustmailerCode = error.metadata.get('rustmailer-error-code')[0];
const category = getErrorCategory(parseInt(rustmailerCode));
handleErrorByCategory(category, error.message);
}

4. Retry Logic Implementation

const RETRYABLE_ERROR_RANGES = [
[40000, 49999], // Network errors
[50000, 59999], // Email service errors
[60000, 69999], // Message queue errors
[70000, 79999], // System errors
];

function isRetryableError(errorCode) {
return RETRYABLE_ERROR_RANGES.some(([min, max]) =>
errorCode >= min && errorCode <= max
);
}

async function apiCallWithRetry(apiCall, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await apiCall();
} catch (error) {
const errorData = await error.response.json();

if (!isRetryableError(errorData.code) || attempt === maxRetries) {
throw error;
}

// Exponential backoff
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, attempt) * 1000)
);
}
}
}

5. User-Friendly Error Messages

const ERROR_MESSAGES = {
// Client Errors
10000: "Please check your input and try again.",
10070: "The file you're trying to upload is too large.",
10080: "The request is taking too long. Please try again.",

// Auth Errors
20000: "Please log in to continue.",
20020: "You've reached your account limit. Please upgrade your plan.",
20030: "Your license has expired. Please renew to continue.",

// Resource Errors
30000: "The requested item could not be found.",
30010: "This item already exists.",
30020: "Too many requests. Please wait a moment and try again.",

// Default messages by category
'CLIENT_ERROR': "There's an issue with your request. Please check and try again.",
'AUTH_ERROR': "Authentication required. Please log in.",
'RESOURCE_ERROR': "The requested resource is not available.",
'NETWORK_ERROR': "Network connectivity issue. Please try again.",
'EMAIL_SERVICE_ERROR': "Email service temporarily unavailable.",
'MESSAGE_QUEUE_ERROR': "Message processing issue. Please try again.",
'SYSTEM_ERROR': "System temporarily unavailable. Please try again later."
};

function getUserFriendlyMessage(errorCode) {
return ERROR_MESSAGES[errorCode] ||
ERROR_MESSAGES[getErrorCategory(errorCode)] ||
"An unexpected error occurred.";
}

Framework Integration Examples

React Error Boundary

class RustMailerErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, errorInfo: null };
}

static getDerivedStateFromError(error) {
return { hasError: true };
}

componentDidCatch(error, errorInfo) {
if (error.response?.data?.code) {
const category = getErrorCategory(error.response.data.code);
this.setState({
errorInfo: {
code: error.response.data.code,
message: getUserFriendlyMessage(error.response.data.code),
category
}
});
}
}

render() {
if (this.state.hasError) {
return <ErrorDisplay errorInfo={this.state.errorInfo} />;
}
return this.props.children;
}
}

Axios Interceptor

axios.interceptors.response.use(
response => response,
error => {
if (error.response?.data?.code) {
const errorCode = error.response.data.code;
const category = getErrorCategory(errorCode);

// Log for debugging
console.error(`RustMailer Error [${errorCode}]:`, error.response.data.message);

// Handle specific error categories
switch (category) {
case 'AUTH_ERROR':
store.dispatch(logout());
router.push('/login');
break;
case 'RESOURCE_ERROR':
if (errorCode === 30020) { // TooManyRequest
// Implement rate limiting UI feedback
showRateLimitWarning();
}
break;
}
}
return Promise.reject(error);
}
);

Monitoring and Debugging

Error Code Metrics

Monitor error patterns by category:

// Track error frequency by category
const errorMetrics = {
CLIENT_ERROR: 0,
AUTH_ERROR: 0,
RESOURCE_ERROR: 0,
NETWORK_ERROR: 0,
EMAIL_SERVICE_ERROR: 0,
MESSAGE_QUEUE_ERROR: 0,
SYSTEM_ERROR: 0
};

function trackError(errorCode) {
const category = getErrorCategory(errorCode);
errorMetrics[category]++;

// Send to monitoring service
analytics.track('api_error', {
error_code: errorCode,
error_category: category,
timestamp: new Date().toISOString()
});
}

Debug Information

For development and debugging:

function logDetailedError(error) {
if (error.response?.data?.code) {
const errorCode = error.response.data.code;
const category = getErrorCategory(errorCode);

console.group(`🚨 RustMailer API Error [${errorCode}]`);
console.log('Category:', category);
console.log('Message:', error.response.data.message);
console.log('HTTP Status:', error.response.status);
console.log('Request URL:', error.config?.url);
console.log('Request Method:', error.config?.method);
console.groupEnd();
}
}