Skip to main content

Error Response Format

All API errors follow a consistent format:
{
  "error": {
    "code": "error_code",
    "message": "Human-readable error message",
    "details": {
      // Additional context (optional)
    }
  },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}

HTTP Status Codes

Status CodeDescription
200Success
201Created
204No Content
400Bad Request
401Unauthorized
403Forbidden
404Not Found
409Conflict
422Unprocessable Entity
429Too Many Requests
500Internal Server Error

Error Codes

Authentication Errors

CodeStatusDescription
unauthorized401Missing or invalid API key
invalid_api_key401API key is malformed or revoked
expired_api_key401API key has expired
forbidden403API key lacks required permissions
{
  "error": {
    "code": "unauthorized",
    "message": "Invalid or missing API key"
  }
}

Validation Errors

CodeStatusDescription
invalid_request400Request body is malformed
missing_field400Required field is missing
invalid_field422Field value is invalid
invalid_format422Field format is incorrect
{
  "error": {
    "code": "missing_field",
    "message": "The 'project_id' field is required",
    "details": {
      "field": "project_id"
    }
  }
}

Resource Errors

CodeStatusDescription
not_found404Resource does not exist
already_exists409Resource already exists
conflict409Operation conflicts with current state
{
  "error": {
    "code": "not_found",
    "message": "Trace not found",
    "details": {
      "trace_id": "abc123"
    }
  }
}

Rate Limit Errors

CodeStatusDescription
rate_limited429Too many requests
{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded. Retry after 60 seconds",
    "details": {
      "retry_after": 60
    }
  }
}

Server Errors

CodeStatusDescription
internal_error500Unexpected server error
service_unavailable503Service temporarily unavailable
{
  "error": {
    "code": "internal_error",
    "message": "An unexpected error occurred"
  }
}

Handling Errors

Python Example

import anyway

try:
    traces = anyway.api.get_traces()
except anyway.AuthenticationError:
    print("Check your API key")
except anyway.RateLimitError as e:
    time.sleep(e.retry_after)
    # Retry the request
except anyway.APIError as e:
    print(f"API error: {e.code} - {e.message}")

HTTP Example

response=$(curl -s -w "\n%{http_code}" \
  https://api.anyway.sh/v1/traces \
  -H "Authorization: Bearer YOUR_API_KEY")

status_code=$(echo "$response" | tail -1)
body=$(echo "$response" | head -n -1)

if [ "$status_code" -eq 429 ]; then
  retry_after=$(echo "$body" | jq -r '.error.details.retry_after')
  sleep $retry_after
  # Retry the request
fi

Request IDs

Every API response includes a request_id in the meta object. Include this ID when contacting support about errors:
Request ID: req_abc123xyz

Best Practices

For transient errors (429, 500, 503), implement exponential backoff:
import time

def retry_with_backoff(func, max_retries=3):
    for attempt in range(max_retries):
        try:
            return func()
        except (RateLimitError, ServerError):
            wait = 2 ** attempt
            time.sleep(wait)
    raise Exception("Max retries exceeded")
Always log the request_id from error responses for debugging.
Check the Retry-After header or retry_after field and wait before retrying.