Skip to content

Error Status Codes

Overview

RNode Server returns proper HTTP status codes for all responses, including errors and timeouts.

HTTP Status Codes

Success Responses

StatusDescriptionWhen Used
200OKNormal successful response
201CreatedResource created successfully
204No ContentSuccess but no content to return

Client Errors (4xx)

StatusDescriptionWhen Used
400Bad RequestInvalid input data or malformed request
401UnauthorizedAuthentication required or failed
403ForbiddenAccess denied, insufficient permissions
404Not FoundRequested resource doesn't exist
405Method Not AllowedHTTP method not supported for this endpoint
408Request TimeoutHandler exceeded timeout limit
409ConflictResource conflict (e.g., duplicate email)
422Unprocessable EntityValid request but semantic errors
429Too Many RequestsRate limit exceeded
451Unavailable For Legal ReasonsContent blocked for legal reasons

Server Errors (5xx)

StatusDescriptionWhen Used
500Internal Server ErrorHandler execution failed or unexpected error
501Not ImplementedFeature not yet implemented
502Bad GatewayUpstream service error
503Service UnavailableService temporarily unavailable
504Gateway TimeoutUpstream service timeout
507Insufficient StorageStorage quota exceeded

Error Response Format

Standard Error Response

json
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": {
      "email": "Invalid email format",
      "password": "Password too short"
    }
  }
}

Timeout Error Response

json
{
  "success": false,
  "error": {
    "code": "TIMEOUT_ERROR",
    "message": "Handler timeout after 5000ms",
    "details": {
      "timeout": 5000,
      "handler": "/api/slow-operation"
    }
  }
}

Common Error Scenarios

Validation Errors (400)

typescript
app.post('/api/users', (req, res) => {
  const { name, email, age } = req.body;
  
  const errors = [];
  
  if (!name || name.trim().length < 2) {
    errors.push('Name must be at least 2 characters long');
  }
  
  if (!email || !email.includes('@')) {
    errors.push('Valid email is required');
  }
  
  if (age && (age < 0 || age > 150)) {
    errors.push('Age must be between 0 and 150');
  }
  
  if (errors.length > 0) {
    return res.status(400).json({
      success: false,
      error: {
        code: 'VALIDATION_ERROR',
        message: 'Validation failed',
        details: errors
      }
    });
  }
  
  // Process valid data...
  res.json({ success: true, message: 'User created' });
});

Authentication Errors (401)

typescript
app.use('/api/protected', (req, res, next) => {
  const token = req.getHeader('authorization');
  
  if (!token) {
    return res.status(401).json({
      success: false,
      error: {
        code: 'AUTHENTICATION_REQUIRED',
        message: 'Authentication token required'
      }
    });
  }
  
  try {
    const user = validateToken(token);
    req.setParam('user', user);
    next();
  } catch (error) {
    res.status(401).json({
      success: false,
      error: {
        code: 'INVALID_TOKEN',
        message: 'Invalid or expired token'
      }
    });
  }
});

Authorization Errors (403)

typescript
app.get('/api/admin/users', (req, res, next) => {
  const user = req.getParam('user');
  
  if (!user || user.role !== 'admin') {
    return res.status(403).json({
      success: false,
      error: {
        code: 'INSUFFICIENT_PERMISSIONS',
        message: 'Admin access required',
        details: {
          requiredRole: 'admin',
          currentRole: user?.role || 'none'
        }
      }
    });
  }
  
  next();
});

Resource Not Found (404)

typescript
app.get('/api/users/{id}', (req, res) => {
  const { id } = req.params;
  const user = findUserById(id);
  
  if (!user) {
    return res.status(404).json({
      success: false,
      error: {
        code: 'USER_NOT_FOUND',
        message: 'User not found',
        details: {
          userId: id,
          searchedAt: new Date().toISOString()
        }
      }
    });
  }
  
  res.json({ success: true, user });
});

Rate Limiting (429)

typescript
const rateLimitStore = new Map();

app.use('/api', (req, res, next) => {
  const clientIP = req.getHeader('x-forwarded-for') || 'unknown';
  const now = Date.now();
  const windowMs = 15 * 60 * 1000; // 15 minutes
  const maxRequests = 100;
  
  let clientData = rateLimitStore.get(clientIP);
  
  if (!clientData) {
    clientData = { requests: [], resetTime: now + windowMs };
    rateLimitStore.set(clientIP, clientData);
  }
  
  // Clean old requests
  clientData.requests = clientData.requests.filter(time => time > now - windowMs);
  
  if (clientData.requests.length >= maxRequests) {
    return res.status(429).json({
      success: false,
      error: {
        code: 'RATE_LIMIT_EXCEEDED',
        message: 'Too many requests',
        details: {
          limit: maxRequests,
          window: windowMs,
          retryAfter: Math.ceil((clientData.resetTime - now) / 1000)
        }
      }
    });
  }
  
  clientData.requests.push(now);
  next();
});

Timeout Errors (408)

typescript
app.get('/api/slow-operation', async (req, res) => {
  try {
    // Simulate slow operation
    const result = await performSlowOperation();
    res.json({ success: true, result });
  } catch (error) {
    if (error.code === 'TIMEOUT') {
      res.status(408).json({
        success: false,
        error: {
          code: 'HANDLER_TIMEOUT',
          message: 'Operation timed out',
          details: {
            timeout: 5000,
            operation: 'performSlowOperation'
          }
        }
      });
    } else {
      res.status(500).json({
        success: false,
        error: {
          code: 'INTERNAL_ERROR',
          message: 'Operation failed'
        }
      });
    }
  }
});

Internal Server Errors (500)

typescript
app.get('/api/risky-operation', async (req, res, next) => {
  try {
    const result = await performRiskyOperation();
    res.json({ success: true, result });
  } catch (error) {
    // Log error for debugging
    console.error('Risky operation failed:', error);
    
    // Pass to error handling middleware
    next(error);
  }
});

// Global error handler
app.use((error, req, res, next) => {
  console.error('Unhandled error:', error);
  
  res.status(500).json({
    success: false,
    error: {
      code: 'INTERNAL_SERVER_ERROR',
      message: process.env.NODE_ENV === 'development' ? error.message : 'Internal server error',
      ...(process.env.NODE_ENV === 'development' && { stack: error.stack })
    }
  });
});

Custom Error Classes

Creating Custom Errors

typescript
class AppError extends Error {
  constructor(
    message: string,
    public statusCode: number = 500,
    public code: string = 'INTERNAL_ERROR',
    public details?: any
  ) {
    super(message);
    this.name = 'AppError';
    
    Error.captureStackTrace(this, this.constructor);
  }
}

class ValidationError extends AppError {
  constructor(message: string, details?: any) {
    super(message, 400, 'VALIDATION_ERROR', details);
  }
}

class AuthenticationError extends AppError {
  constructor(message: string = 'Authentication failed') {
    super(message, 401, 'AUTHENTICATION_ERROR');
  }
}

class AuthorizationError extends AppError {
  constructor(message: string = 'Access denied') {
    super(message, 403, 'AUTHORIZATION_ERROR');
  }
}

class NotFoundError extends AppError {
  constructor(resource: string = 'Resource') {
    super(`${resource} not found`, 404, 'NOT_FOUND');
  }
}

Using Custom Errors

typescript
app.get('/api/users/{id}', (req, res, next) => {
  try {
    const { id } = req.params;
    const user = findUserById(id);
    
    if (!user) {
      throw new NotFoundError('User');
    }
    
    if (!req.getParam('isAuthenticated')) {
      throw new AuthenticationError();
    }
    
    if (user.id !== req.getParam('userId') && req.getParam('userRole') !== 'admin') {
      throw new AuthorizationError('Cannot access other users');
    }
    
    res.json({ success: true, user });
  } catch (error) {
    if (error instanceof AppError) {
      res.status(error.statusCode).json({
        success: false,
        error: {
          code: error.code,
          message: error.message,
          ...(error.details && { details: error.details })
        }
      });
    } else {
      next(error);
    }
  }
});

Error Handling Best Practices

Consistent Error Format

Always return errors in the same format for consistency.

Appropriate Status Codes

Use the most specific status code that matches the error condition.

Detailed Error Messages

Provide helpful error messages for debugging (but not in production).

Error Logging

Log errors appropriately for monitoring and debugging.

Client-Friendly Messages

Return user-friendly error messages while logging technical details.

Error Recovery

Provide guidance on how to resolve the error when possible.

Next Steps

Released under the MIT License.