Error Handling¶
Continuum Router returns OpenAI-compatible JSON errors at the HTTP boundary and uses retries, active health filtering, and model fallback to contain transient backend failures.
Error response format¶
Most router-generated failures use this shape:
{
"error": {
"message": "The service is temporarily unavailable. Please try again later.",
"type": "service_unavailable",
"code": 503
}
}
param is included when the upstream provider supplies it. A rate-limited response may also include Retry-After.
Streaming failures that happen before any bytes are sent use an HTTP error response. Once an SSE response has started, the stream reports an error event and terminates; the status code can no longer be changed.
Status codes¶
| Status | Typical cause | Retry guidance |
|---|---|---|
400 |
Invalid request or provider rejected the parameters | Correct the request |
401 |
Missing or invalid credentials | Correct authentication |
403 |
Authenticated caller is not allowed to use the requested resource | Correct permissions or key policy |
404 |
Requested model or stored response was not found | Check the identifier |
408 |
Router request deadline expired | Retry only when safe for the operation |
413 |
Request body exceeded the configured limit | Reduce the request size |
429 |
Router/provider rate limit or exhausted quota | Honor Retry-After; quota failures are not retried automatically |
500 |
Router configuration or internal failure | Inspect logs and configuration |
502 |
Backend connection, stream, or gateway failure | Usually transient |
503 |
Backend unavailable or all eligible backends unhealthy | Usually transient |
504 |
Backend timeout | Usually transient |
Provider error bodies are normalized when possible. For unrecognized provider 4xx responses, the router keeps only a bounded message excerpt and does not expose arbitrary internal data.
Retries¶
The top-level retry section controls retries to the selected backend:
retry:
max_attempts: 3
initial_delay: 100ms
max_delay: 10s
backoff_multiplier: 2.0
jitter: true
retryable_status_codes: [429, 502, 503, 504]
retryable_errors: [ConnectionError, TimeoutError]
timeout: 30s
These are also the default values. The router applies exponential backoff with optional jitter. A provider 429 is retried only when it is classified as a transient rate limit; quota, credit, and billing exhaustion fail fast. Upstream Retry-After or Google retry-delay hints are honored after validation and are capped at 24 hours.
Retries repeat an attempt against a backend. They are distinct from fallback, which can select another model or provider after an eligible failure.
Circuit breaker¶
Continuum Router includes a configurable three-state circuit-breaker implementation and Admin controls:
circuit_breaker:
enabled: true
failure_threshold: 5
failure_rate_threshold: 0.5
minimum_requests: 10
timeout: 60s
half_open_max_requests: 3
half_open_success_threshold: 2
failure_status_codes: [500, 502, 503, 504]
timeout_as_failure: true
sliding_window_size: 60s
sliding_window_type: count_based
backends:
openai:
failure_threshold: 10
timeout: 120s
sliding_window_type accepts count_based or time_based. Entries below circuit_breaker.backends override only the supported per-backend fields.
The regular LLM proxy path records request outcomes in this state machine and consults it during backend selection: an open backend circuit is excluded from selection, and when every compatible circuit is open the router returns a 503 service-unavailable error and participates in configured fallback. It complements active health checks, retries, and fallback rather than replacing them. See Circuit Breaker for the outcome-recording and admission details.
When Admin API authentication permits access, operators can inspect or control breaker state through:
| Method | Path | Purpose |
|---|---|---|
GET |
/admin/circuit/all |
List all breaker states |
GET |
/admin/circuit/{backend}/status |
Get one backend's state |
POST |
/admin/circuit/{backend}/open |
Force the circuit open |
POST |
/admin/circuit/{backend}/close |
Force the circuit closed |
POST |
/admin/circuit/{backend}/reset |
Reset tracked breaker state |
See Admin API for authentication and complete endpoint details.
Model fallback¶
Fallback chains choose alternative models after configured failure conditions:
fallback:
enabled: true
mid_stream_enabled: true
fallback_chains:
gpt-5.4:
- gpt-5.4-mini
- claude-sonnet-4-6
fallback_policy:
trigger_conditions:
error_codes: [429, 500, 502, 503, 504]
timeout: true
connection_error: true
model_not_found: true
backend_unhealthy: true
max_fallback_attempts: 3
fallback_timeout_multiplier: 1.5
preserve_parameters: true
model_settings:
gpt-5.4:
fallback_enabled: true
notify_on_fallback: true
With notify_on_fallback: true (the default), successful fallback responses can contain:
X-Fallback-UsedX-Original-ModelX-Fallback-ModelX-Fallback-ReasonX-Fallback-Attempts— total model attempts including the primary; always at least 2 when a fallback served the response
Set notify_on_fallback: false for a model to suppress these headers while still serving the fallback.
Cross-provider fallback translates the supported request parameters; provider-only parameters that cannot be represented may be removed.
mid_stream_enabled: true permits mid-stream recovery where the streaming path supports it. It may buffer output, so disable it when immediate token delivery is more important than recovery after a stream has begun.
Timeouts and request size¶
Configure router and model deadlines in the timeouts section and backend request limits in the documented server/backend sections. Avoid making retry timeouts longer than the caller's total deadline; the caller can otherwise disconnect while retry work continues.
Use the generated configuration as the canonical field reference:
Observability and diagnosis¶
Use implemented interfaces rather than undocumented debug endpoints:
# Public process/backend health
curl http://localhost:8080/health
# Admin health and circuit state (add configured admin credentials)
curl http://localhost:8080/admin/health
curl http://localhost:8080/admin/circuit/all
# Validate configuration without starting the server
continuum-router config validate /etc/continuum-router/config.yaml
Prometheus metrics are exposed at the configured metrics path when the metrics feature and runtime metrics configuration are enabled. Logs use tracing; select verbosity with logging.level, CONTINUUM_LOG_LEVEL, or RUST_LOG as appropriate.
The router does not provide /admin/errors/* or /admin/debug/error endpoints. Inspect structured logs, metrics, /admin/health, and /admin/circuit/* instead.
Client recommendations¶
- Set a caller-side deadline longer than the expected router/backend timeout.
- Retry only idempotent operations unless your application has deduplication.
- Use exponential backoff with jitter and honor
Retry-After. - Do not retry authentication, permission, validation, or quota-exhaustion errors without changing the request or credentials.
- Record a correlation/request identifier from your own client logs and avoid logging API keys or resolved configuration output.