Skip to Content
APIError Logging

Error Logging

The Curate-Me API uses a consistent error format across all endpoints. Production errors are tracked in a centralized logging system that supports querying, resolution tracking, and CLI-based management.

Error Response Format

All API errors return a structured JSON response in the OpenAI-compatible envelope:

{ "error": { "message": "Estimated cost $3.50 exceeds per-request limit $2.00", "type": "permission_error", "param": null, "code": "cost_limit" } }
FieldTypeDescription
error.messagestringHuman-readable error description
error.typestringError category (e.g. permission_error, rate_limit_error, authentication_error)
error.paramstring or nullThe request parameter that caused the error, if applicable
error.codestringMachine-readable error code for programmatic handling

For the full type/code catalog, see the Gateway Error Reference.

Error Codes

CodeHTTP StatusDescription
invalid_api_key401Missing or invalid Curate-Me API key
missing_provider_key401No provider API key supplied and no stored secret exists
key_rotated401The API key has been rotated; use the replacement key
invalid_json400Request body is not valid JSON
missing_model400The model field is missing from the request body
unknown_model400The model is not recognized by the gateway
provider_mismatch400The model does not belong to the provider endpoint it was sent to
model_retired400The requested model has been retired
cost_limit403Estimated cost exceeds the per-request cap
daily_budget403The organization’s daily budget has been exhausted
monthly_budget403The organization’s monthly budget has been exhausted
pii_detected403PII or secrets were detected in the request content
model_not_allowed403The model is not in the organization’s allowlist
needs_approval403 / 202The request requires human (HITL) approval before execution
request_too_large413Request body exceeds the tier’s body-size limit
rate_limit429The requests-per-minute (RPM) limit has been exceeded
plan_limit_exceeded429The plan’s daily request quota or budget has been exhausted
internal_error500Unexpected error within the gateway
connection_error502Failed to connect to the upstream provider
circuit_breaker_open503The provider’s circuit breaker is open after repeated failures
timeout504The upstream provider timed out

HTTP Status Codes

StatusMeaningCommon Causes
400Bad RequestInvalid JSON, missing fields, provider mismatch, retired model
401UnauthorizedMissing or invalid API key or access token
403ForbiddenBlocked by governance (cost, budget, PII, model allowlist, HITL)
404Not FoundResource does not exist or was deleted
409ConflictDuplicate resource creation
410GoneEndpoint or model has been retired
413Payload Too LargeRequest body exceeds the tier body-size limit
429Too Many RequestsRate limit exceeded or plan quota exhausted; includes Retry-After
500Internal Server ErrorUnexpected gateway error
502Bad GatewayUpstream LLM provider is unavailable
503Service UnavailableCircuit breaker open or scheduled maintenance
504Gateway TimeoutUpstream provider timed out

Error Log CLI

The platform includes a CLI tool for querying and managing production errors. This requires an ERROR_LOG_API_KEY configured in your environment.

First-Time Setup

./scripts/errors setup # Enter your ERROR_LOG_API_KEY when prompted # Key is stored in ~/.curateme-error-key (not committed to git)

View Recent Errors

./scripts/errors recent

Output:

ID | Time | Code | Message ------------|---------------------|--------------------|--------------------------------- err_abc123 | 2026-02-08 14:23:00 | rate_limit | RPM limit exceeded (OpenAI) err_def456 | 2026-02-08 14:10:00 | daily_budget | Daily budget exhausted err_ghi789 | 2026-02-08 13:55:00 | pii_detected | Credit card number in request body

Get Error Details

./scripts/errors get err_abc123

Returns the full error record including stack trace, request context, and governance decision state.

Get Error Statistics

./scripts/errors summary

Output:

Error Summary (last 24h) ------------------------ Total errors: 47 Unresolved: 12 Top error codes: rate_limit: 18 (38%) daily_budget: 15 (32%) pii_detected: 8 (17%) upstream_502: 6 (13%)

Resolve an Error

After fixing the root cause and deploying, mark the error as resolved:

./scripts/errors resolve err_abc123 "Raised the org's RPM limit (PR #142)"

Error Handling Best Practices

When integrating with the API, implement error handling that accounts for the following:

  1. Retry on 429 and 503 — Use the Retry-After header value for backoff timing.
  2. Do not retry on 400 or 401 — These indicate client-side issues that require changes to the request.
  3. Handle SSE errors — During streaming responses, listen for error events and handle them gracefully.
  4. Log the error code — Use the error.code field for programmatic error handling rather than parsing the message string.
// Pattern shown against the gateway proxy endpoint — the same shape works // for the admin REST surface. try { const response = await fetch( 'https://api.curate-me.ai/v1/openai/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CM-API-Key': process.env.CURATE_ME_API_KEY, }, body: JSON.stringify({ model: 'gpt-4o-mini', messages: [{ role: 'user', content: 'Hello' }], }), }, ); if (!response.ok) { const { error } = await response.json(); switch (error.code) { case 'rate_limit': const retryAfter = response.headers.get('Retry-After'); await delay(Number(retryAfter) * 1000); return retry(request); case 'invalid_api_key': await refreshKey(); return retry(request); default: throw new ApiError(error.code, error.message); } } } catch (err) { // Network or unexpected errors console.error('API request failed:', err); }