Skip to content

Error Handling

Understanding and handling API errors effectively.

Error Response Format

All API errors return consistent JSON structure:

json
{
  "statusCode": 400,
  "message": "Validation failed",
  "error": "Bad Request",
  "timestamp": "2024-01-20T15:30:00Z",
  "path": "/api/v1/servers",
  "details": [
    {
      "field": "port",
      "message": "Port must be between 1024 and 65535",
      "value": 80
    }
  ]
}

HTTP Status Codes

4xx Client Errors

400 Bad Request

Invalid request parameters or body.

Common causes:

  • Missing required fields
  • Invalid field values
  • Malformed JSON

Example:

json
{
  "statusCode": 400,
  "message": "Validation failed",
  "error": "Bad Request",
  "details": [
    {
      "field": "name",
      "message": "Name is required"
    }
  ]
}

Solution:

  • Verify request body matches API schema
  • Check all required fields are present
  • Validate field types and formats

401 Unauthorized

Missing or invalid authentication token.

Common causes:

  • Missing Authorization header
  • Expired token
  • Revoked token
  • Invalid token format

Example:

json
{
  "statusCode": 401,
  "message": "Unauthorized",
  "error": "Invalid or expired token"
}

Solution:

  • Include Authorization: Bearer <token> header
  • Verify token hasn't expired
  • Create new token if revoked
  • Check token format: arcadium_live_...

403 Forbidden

Valid token but insufficient permissions.

Common causes:

  • Cluster role lacks permission
  • Not a member of cluster
  • Resource belongs to different cluster

Example:

json
{
  "statusCode": 403,
  "message": "Forbidden",
  "error": "Insufficient permissions for this resource"
}

Solution:

  • Request role promotion from cluster admin
  • Verify cluster membership
  • Use token with appropriate permissions

404 Not Found

Requested resource doesn't exist.

Example:

json
{
  "statusCode": 404,
  "message": "Not Found",
  "error": "Server not found"
}

Solution:

  • Verify resource ID is correct
  • Check resource wasn't deleted
  • Ensure you have access to the cluster

409 Conflict

Request conflicts with current state.

Common causes:

  • Duplicate resource (e.g., port already in use)
  • Invalid state transition (e.g., starting stopped server)
  • Concurrent modification

Example:

json
{
  "statusCode": 409,
  "message": "Conflict",
  "error": "Port 27015 already in use by another server"
}

Solution:

  • Choose different port/name
  • Wait for operation to complete
  • Refresh resource state before retry

429 Too Many Requests

Rate limit exceeded.

Example:

json
{
  "statusCode": 429,
  "message": "Too Many Requests",
  "error": "Rate limit exceeded, retry after 30 seconds",
  "retryAfter": 30
}

Solution:

  • Implement exponential backoff
  • Respect Retry-After header
  • Reduce request frequency

5xx Server Errors

500 Internal Server Error

Unexpected server error.

Example:

json
{
  "statusCode": 500,
  "message": "Internal Server Error",
  "error": "An unexpected error occurred",
  "errorId": "err_abc123"
}

Solution:

  • Retry request with backoff
  • Contact support with errorId if persistent
  • Check status page for incidents

503 Service Unavailable

Service temporarily unavailable.

Common causes:

  • Planned maintenance
  • Server overload
  • Dependency failure

Solution:

  • Retry with exponential backoff
  • Check status page
  • Wait for service restoration

Validation Errors

Detailed field-level validation errors:

json
{
  "statusCode": 400,
  "message": "Validation failed",
  "error": "Bad Request",
  "details": [
    {
      "field": "port",
      "message": "Port must be between 1024 and 65535",
      "value": 80
    },
    {
      "field": "maxPlayers",
      "message": "Must be a positive integer",
      "value": -5
    }
  ]
}

Error Handling Patterns

Retry Logic

javascript
async function apiRequest(url, options, maxRetries = 3) {
  let lastError;
  
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      
      if (response.ok) {
        return await response.json();
      }
      
      // Don't retry client errors (except 429)
      if (response.status >= 400 && response.status < 500 && response.status !== 429) {
        throw await response.json();
      }
      
      lastError = await response.json();
      
      // Exponential backoff
      await sleep(Math.pow(2, i) * 1000);
      
    } catch (error) {
      lastError = error;
    }
  }
  
  throw lastError;
}

Rate Limit Handling

javascript
async function handleRateLimit(response) {
  if (response.status === 429) {
    const retryAfter = response.headers.get('Retry-After') || 30;
    await sleep(retryAfter * 1000);
    return true; // Retry
  }
  return false;
}

Error Recovery

typescript
try {
  const server = await api.servers.create(data);
} catch (error) {
  if (error.statusCode === 409 && error.message.includes('port')) {
    // Port conflict - try next port
    data.port += 1;
    return retry();
  }
  
  if (error.statusCode === 401) {
    // Token expired - refresh and retry
    await refreshToken();
    return retry();
  }
  
  // Other errors - surface to user
  throw error;
}

WebSocket Errors

WebSocket-specific error events:

json
{
  "event": "error",
  "data": {
    "code": "COMMAND_FAILED",
    "message": "Failed to start server",
    "details": {
      "serverId": "srv_xyz",
      "reason": "Port already in use"
    }
  }
}

Common WebSocket Errors

CodeDescriptionSolution
AUTH_FAILEDAuthentication failedCheck token validity
AUTH_TIMEOUTNo auth within 10sSend auth immediately after connect
INVALID_MESSAGEMalformed messageValidate JSON format
COMMAND_FAILEDCommand execution failedCheck command parameters
RATE_LIMITToo many messagesReduce message frequency

Best Practices

1. Always Handle Errors

typescript
// ❌ Bad
const server = await api.servers.get(id);

// ✅ Good
try {
  const server = await api.servers.get(id);
} catch (error) {
  if (error.statusCode === 404) {
    console.log('Server not found');
  } else {
    console.error('Failed to fetch server:', error);
  }
}

2. Implement Retry Logic

For transient errors (5xx, network errors):

  • Use exponential backoff
  • Set maximum retry count
  • Log failures

3. Respect Rate Limits

  • Cache responses when possible
  • Batch requests
  • Use WebSocket for real-time data

4. Provide User Feedback

typescript
catch (error) {
  const userMessage = {
    400: 'Please check your input',
    401: 'Please log in again',
    403: 'You don\'t have permission',
    404: 'Resource not found',
    429: 'Too many requests, please wait',
    500: 'Server error, please try again'
  }[error.statusCode] || 'An error occurred';
  
  showNotification(userMessage);
}

5. Log Error Details

Include error ID for support:

typescript
console.error('API Error:', {
  errorId: error.errorId,
  statusCode: error.statusCode,
  message: error.message,
  endpoint: error.path
});

Next Steps

Released under the MIT License.