Tillered Arctic

Error Codes

API error codes and handling

API Error Codes

The Arctic API returns errors with HTTP status codes and JSON error bodies.

Error Response Format

{
  "error": "human-readable message",
  "code": "ERROR_CODE"
}

HTTP Status Codes

StatusDescription
400Bad Request - Invalid input
401Unauthorized - Authentication required
403Forbidden - Insufficient permissions
404Not Found - Resource does not exist
409Conflict - Resource already exists
422Unprocessable Entity - Validation error
500Internal Server Error

Error Codes

Authentication Errors

CodeStatusDescription
UNAUTHORIZED401Token missing or invalid
TOKEN_EXPIRED401Token has expired
FORBIDDEN403Insufficient scope

Resource Errors

CodeStatusDescription
NOT_FOUND404Resource not found
ALREADY_EXISTS409Resource already exists
ALREADY_BOOTSTRAPPED409Agent already initialized

Validation Errors

CodeStatusDescription
INVALID_REQUEST400Malformed request body
INVALID_CIDR400Invalid CIDR notation
MISSING_FIELD400Required field missing
INVALID_TRANSPORT400Transport must be tcp or kcp

Limit Errors

CodeStatusDescription
NODE_LIMIT_EXCEEDED422License node limit reached
SERVICE_LIMIT_EXCEEDED422License service limit reached

License Errors

CodeStatusDescription
LICENSE_EXPIRED422License has expired
LICENSE_INVALID422Invalid license signature
LICENSE_MISMATCH422License ID mismatch

Cluster Errors

CodeStatusDescription
HANDSHAKE_FAILED422Peer handshake failed
PEER_UNREACHABLE422Cannot connect to peer

Error Handling Examples

Check for Specific Error

const response = await fetch('/v1/peers', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${token}` },
  body: JSON.stringify({ address: '192.168.1.20:8080' })
});

if (!response.ok) {
  const error = await response.json();

  switch (error.code) {
    case 'ALREADY_EXISTS':
      console.log('Peer already in cluster');
      break;
    case 'NODE_LIMIT_EXCEEDED':
      console.log('Upgrade license for more nodes');
      break;
    case 'HANDSHAKE_FAILED':
      console.log('Check network connectivity');
      break;
    default:
      console.log(`Error: ${error.error}`);
  }
}

Retry on Transient Errors

async function apiCall(url, options, retries = 3) {
  for (let i = 0; i < retries; i++) {
    const response = await fetch(url, options);

    if (response.ok) return response.json();

    if (response.status >= 500) {
      // Retry on server errors
      await sleep(1000 * (i + 1));
      continue;
    }

    // Don't retry client errors
    const error = await response.json();
    throw new Error(error.error);
  }
  throw new Error('Max retries exceeded');
}