Skip to main content

Error Handling

All errors from DVARA use a consistent JSON envelope regardless of which surface returned them. Three separate services emit errors, and the tables below are grouped by source so that every row maps to behavior that actually runs:

  • Data plane errors — DVARA LLM Gateway on port 8080, serving /v1/chat/completions, /v1/embeddings, /v1/models, and the actuator surface (/actuator/health, /actuator/gateway-status, /actuator/prometheus).
  • Admin API errors — DVARA Flightdeck on port 8090, serving /v1/admin/*.
  • MCP Proxy errors — DVARA MCP Proxy on port 8070, serving MCP tool calls. Approval-gate, loop-detection, and other agentic errors share the same envelope shape as the rest of the MCP errors below.

A single error code lives in exactly one of these three tables — there's no global "500-row catalog". If you can't find a code below, it means it isn't reachable on the surface you're looking at.

Error Envelope

{
"error": {
"message": "Human-readable description of the error",
"type": "invalid_request_error | provider_error | gateway_error",
"code": "machine-readable error code",
"param": "field name, if validation error",
"trace_id": "32-character hex trace ID"
}
}
FieldTypeDescription
messagestringHuman-readable error description
typestringError category (see table below)
codestringMachine-readable error code
paramstringField name that caused the error (validation only)
trace_idstring32-character hex trace ID for debugging

Data plane errors

Emitted by the DVARA LLM Gateway on port 8080 for every /v1/* request.

StatustypecodeWhen
400invalid_request_errorvalidation_errorMissing required field on the request DTO (model, messages). Emitted by request-body validation, before the gateway's exception path.
400invalid_request_errorno_providerNo provider on the route matches the requested model, or the matching provider has no credential configured.
400invalid_request_errorno_capable_providerThe route has providers but none of them support the requested response_format.
400invalid_request_errorinvalid_requestGeneric request-shape rejection (missing response_format.type, etc.) after the body has parsed successfully.
400invalid_request_errorinvalid_jsonMalformed JSON body — parsing failed before request-DTO binding. Emitted by Spring's HttpMessageNotReadableException handler.
400invalid_request_errorunsupported_response_formatDefensive provider-level check for response_format types the provider can't handle. In normal flow, capability-aware routing intercepts these requests first and returns no_capable_provider; this code surfaces only when routing bypasses capability filtering (for example, explicit model-prefix routing).
400invalid_request_errorunsupported_capabilityThe selected provider does not support the content in the request. Raised by Cohere, Groq, and Ollama for image content (vision) and for tool-use / tool-result content blocks. Capability-aware routing does not pre-filter vision or tool-call content, so the provider itself rejects the request.
400context_window_errorcontext_window_exceededEstimated input tokens exceed the model's context window and no tenant pruning strategy is configured.
400pii_violationpii_detectedPII detected in the request and the tenant policy is BLOCK.
402budget_exceededbudget_cap_hardHard budget cap reached on the tenant or the API key.
402token_cap_exceededlicense_token_cap_exceededPer-tier monthly token cap exceeded — the entitlement-side counterpart to budget_cap_hard. The response body adds four extra fields (upgrade_url, current_usage, cap, tier) so a customer-facing app can render an upgrade CTA inline without a separate Flightdeck round-trip.
403policy_violationpolicy_deniedRequest blocked by an active policy rule.
403guardrail_violationguardrail_blockedGuardrail detector flagged the request at or above the configured risk threshold and the tenant action is BLOCK.
403data_residency_errordata_residency_violationGeo-aware routing found no provider in the tenant's allowed regions.
403ip_access_errorip_access_deniedClient IP blocked by global or per-tenant CIDR rule.
403tenant_credential_requiredtenant_credential_requiredStrict-BYOK enforcement rejected the call — the tenant has no own active provider credential. Set under dvara.credentials.require-tenant-credential=true (global) or Tenant.metadata["credentials.require-tenant-credential"] (per-tenant). Audit event: PROVIDER_CREDENTIAL_MISSING.
403tenant_cap_exceededtenant_cap_exceededPer-tier tenant-count cap exceeded — the customer is trying to provision more tenants than their license tier allows. The exception message carries the upgrade URL.
403tenant_suspendedtenant_suspendedTenant administratively suspended — trial-cliff expiry, chronic-abuse sweep, self-delete schedule, or manual operator action. Audit event per blocked request: TENANT_SUSPENDED_BLOCK.
413input_size_errorinput_too_largeRequest exceeds guardrail.max-input-tokens, guardrail.max-messages-per-request, or guardrail.max-message-length.
422schema_validation_errorschema_validation_failedOutput schema validation failed after the configured max retries.
429rate_limit_errorrate_limit_exceededPer-key request count or token budget exhausted in the current 60-second window. Emitted directly by the rate-limit filter.
429priority_throttle_errorpriority_throttledPriority admission controller rejected the request because the tenant's tier is over its concurrency threshold.
502provider_errorprovider_errorUpstream provider returned a non-success status, or the connection failed, after retries and failover. Provider-specific detail is prefixed to the message.
503provider_unavailableprovider_circuit_openThe provider's circuit breaker is OPEN; no upstream call was attempted.
503provider_unavailablefailover_capability_mismatchPrimary provider failed and no capable fallback exists. Response also carries the X-Gateway-Failover-Blocked: capability_mismatch header.

Prompt-template codes (data plane)

Emitted when a request references a template via metadata.prompt_template_id and the resolver can't satisfy the reference.

StatustypecodeWhen
400invalid_request_errorprompt_template_not_activeReferenced template is not in ACTIVE status.
400invalid_request_errorprompt_variable_missingRequired {{variable}} not provided in the request's variables map.

Additional guardrail error codes

StatustypecodeWhen
403guardrail_violationhallucination_detectedThe grounding-detection layer fires with action: BLOCK — response contains ungrounded claims.
500guardrail_plugin_errorguardrail_plugin_errorAn external guardrail plugin configured with fail-mode: CLOSED failed to complete its call.

Admin API errors

Emitted by the DVARA Flightdeck on port 8090 for every /v1/admin/* request. Same envelope shape as the data plane, same lowercased-code convention.

Authentication and authorization

StatustypecodeWhen
401unauthorized_errorauthentication_requiredAdmin caller missing or invalid Bearer token / PAT / JWT. Emitted by Spring Security's AuthenticationException path.
403forbidden_erroraccess_deniedTenant-scope violation: a tenant-role caller (admin / developer / viewer) tried to read or write a resource belonging to another tenant, or a caller lacked the URL-pattern RBAC role required for the path. Emits a TENANT_SCOPE_VIOLATION audit event capturing the path, method, requested tenant id, and acting principal — security teams can detect probing without grepping response logs.

Request validation and parsing

StatustypecodeWhen
400invalid_request_errorvalidation_errorMissing required field on the admin request DTO (e.g. name, email). Emitted by Spring's MethodArgumentNotValidException handler.
400invalid_request_errorinvalid_jsonMalformed JSON request body — parsing failed before DTO binding.

Not-found codes (all 404 not_found_error)

Every admin resource that supports GET /{id} returns this shape when the ID doesn't exist or belongs to a different tenant than the caller's RBAC scope allows:

tenant_not_found · api_key_not_found · route_not_found · route_version_not_found · policy_not_found · policy_version_not_found · user_not_found · credential_not_found · pricing_not_found · budget_not_found · chargeback_not_found · report_not_found · webhook_not_found · mcp_server_not_found · schema_not_found · session_not_found · prompt_template_not_found · prompt_version_not_found · prompt_experiment_not_found · mock_scenario_not_found · golden_prompt_not_found · drift_report_not_found · eval_prompt_not_found · eval_report_not_found

Request-shape and license-gate codes

StatustypecodeWhen
400invalid_request_errorinvalid_requestGeneric request-shape rejection.
400invalid_request_errorinvalid_policy_statusPolicy status change target is not a valid lifecycle value.
400invalid_request_errorinvalid_template_statusTemplate status change target is not a valid lifecycle value.
400invalid_request_errorinvalid_report_typeCompliance report type is not one of SOC2 / HIPAA / GDPR.
400invalid_request_errorcompliance_not_availableCompliance reports require an enterprise license key.
400invalid_request_errorchargeback_not_availableChargeback reports require an enterprise license key.
400invalid_request_errormcp_not_availableMCP features require an enterprise license key.
400invalid_request_errorencryption_not_configuredDVARA_ENCRYPTION_MASTER_PASSWORD is not set, so credential or guardrail-plugin secrets cannot be encrypted for storage.
400invalid_request_errorprompt_experiment_not_runningExperiment is not in RUNNING status.
400invalid_request_errormock_scenario_invalid_nameScenario filename failed path-traversal validation.
400invalid_request_errormock_scenario_invalidScenario Groovy source failed compile-check.
400invalid_request_errorinvalid_output_schema_scopeRegistered output schema must declare a routeId, a modelPattern, or both — neither would never match any request.
400invalid_request_errorinvalid_policy_dslPolicy YAML DSL failed compile-check (syntax error, unknown condition, unknown action).
400invalid_request_errorinvalid_storage_modeCredential storageMode is not one of ENCRYPTED / REFERENCE.
400invalid_request_errorcredential_api_key_missingPOST /v1/admin/credentials or rotate with storageMode=ENCRYPTED but no apiKey field in the body.
400invalid_request_errorcredential_reference_missingPOST /v1/admin/credentials or rotate with storageMode=REFERENCE but no secretReference field in the body.
400invalid_request_errorcredential_storage_mode_mismatchRotate request used the wrong field for the credential's current storage mode (e.g. passed apiKey on a REFERENCE credential).
400invalid_request_errorcredential_not_rotatableTried to rotate a credential that isn't in ACTIVE status (e.g. already REVOKED or SUPERSEDED).
409duplicate_errormcp_server_duplicateServer ID already exists for the target tenant.
409duplicate_erroruser_duplicateUser email already exists for the target tenant.
413payload_too_largemock_scenario_too_largeScenario source exceeded the 256 KB limit.
500admin_errorDefault fall-through for any unmatched gateway-thrown error.

MCP Proxy errors

Emitted by the DVARA MCP Proxy on port 8070. Every error — auth, policy, agentic governance, upstream failure — comes back through the same lowercase-code, type: "mcp_error" envelope:

{
"error": {
"message": "…",
"type": "mcp_error",
"code": "mcp_server_not_found",
"trace_id": "…"
}
}
StatuscodeWhen
400mcp_not_availableMCP Proxy requires an enterprise license.
400mcp_pii_detectedPII detected in the tool-call arguments or response, tenant policy is BLOCK.
401mcp_auth_requiredMissing Authorization: Bearer <key> on the MCP Proxy request.
401mcp_auth_invalidAPI key does not resolve to an active tenant.
401mcp_auth_revokedAPI key has been revoked.
403mcp_policy_deniedMCP request denied by a policy rule.
403mcp_approval_deniedA human reviewer denied the tool call from the DVARA Flightdeck approval queue.
403mcp_agent_session_killedThe session has been terminated by POST /v1/admin/sessions/{id}/kill; subsequent tool calls for that session return immediately.
404mcp_not_foundWrong URL on port 8070 (e.g. typo, excluded actuator path, bot probe). Returned by the generic NoResourceFoundException / NoHandlerFoundException handler so probes to non-existent paths don't masquerade as 500 mcp_internal_error.
404mcp_server_not_foundMCP server ID not registered for the calling tenant.
408mcp_approval_timeoutApproval gate reached its configured timeout with no human decision; tenant default action is deny.
429mcp_rate_limit_exceededPer-key rate limit exhausted.
429mcp_agent_loop_detectedThe loop detector fired (repetition threshold, cycle detection, or rate cap) on the session.
502(fall-through)Any other gateway-thrown error code; the MCP Proxy lowercases it, prefixes mcp_ if needed, and returns 502 mcp_error / mcp_<code>.
503mcp_server_unavailableMCP server is suspended, disabled, or the circuit breaker is open.
500mcp_internal_errorAny unhandled exception — caught by the generic handler branch.

Error Examples

Validation Error — Missing Model

curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"messages": [{"role": "user", "content": "Hi"}]}'
{
"error": {
"message": "model is required",
"type": "invalid_request_error",
"code": "validation_error",
"param": "model",
"trace_id": "a6783439db1f46a6bfed511a0011e955"
}
}

No Provider Configured

{
"error": {
"message": "No provider configured for model: gpt-4o. Set dvara.llm-gateway.providers.<name>.api-key in application.yml or as an env var.",
"type": "invalid_request_error",
"code": "no_provider",
"trace_id": "d354d2faaa5f4e14939aa8c480fb9d90"
}
}

Unsupported Response Format

{
"error": {
"message": "Ollama provider does not support response_format. Supported formats: [text]",
"type": "invalid_request_error",
"code": "unsupported_response_format"
}
}

Tenant Not Found

{
"error": {
"message": "Tenant not found: t-999",
"type": "not_found_error",
"code": "tenant_not_found",
"trace_id": "e9016783ab4c5d60c3ff042e3h3h7266"
}
}

Credential Not Found

{
"error": {
"message": "Required credential not found: provider.openai.api-key",
"type": "invalid_request_error",
"code": "credential_not_found",
"trace_id": "f1234567890abcdef1234567890abcde"
}
}

Rate Limit Exceeded

HTTP/1.1 429 Too Many Requests
Retry-After: 1
X-Trace-ID: a6783439db1f46a6bfed511a0011e955
{
"error": {
"message": "Rate limit exceeded",
"type": "rate_limit_error",
"code": "rate_limit_exceeded",
"trace_id": "a6783439db1f46a6bfed511a0011e955"
}
}

Provider Error

Error messages include a human-readable hint for common HTTP status codes:

{
"error": {
"message": "Anthropic API error 401 (invalid API key — check your provider credentials)",
"type": "provider_error",
"code": "provider_error",
"trace_id": "b7894561cd2e4f38a1cc820d1f1f5044"
}
}

Hints are appended for these status codes:

StatusHint
401invalid API key — check your provider credentials
403access denied — your API key may lack required permissions
404model or endpoint not found — check the model name
429rate limited by provider — too many requests
500provider internal server error
502provider returned bad gateway
503provider is temporarily unavailable

Circuit Breaker Open

When a provider fails repeatedly, the gateway stops sending requests to it temporarily to avoid cascading failures. The error message explains what happened and what to do:

{
"error": {
"message": "Provider anthropic is temporarily unavailable — too many recent requests failed, so new requests are paused. This usually resolves automatically after a short cooldown. If it persists, check your provider API key and account status.",
"type": "provider_unavailable",
"code": "provider_circuit_open",
"trace_id": "c8905672de3f5049b2dd931e2g2g6155"
}
}

PII Detected (Block Mode)

{
"error": {
"message": "PII detected in request — 2 entity type(s) found. Tenant policy: BLOCK",
"type": "pii_violation",
"code": "pii_detected",
"trace_id": "g0127894ab5c6d71e4ff153f4i4i8377"
}
}

Guardrail Blocked

{
"error": {
"message": "Request blocked: guardrail violation detected (INJECTION, JAILBREAK)",
"type": "guardrail_violation",
"code": "guardrail_blocked",
"trace_id": "h1238905bc6d7e82f5gg264g5j5j9488"
}
}

Input Too Large

{
"error": {
"message": "Request exceeds maximum messages limit: 150 > 100",
"type": "input_size_error",
"code": "input_too_large",
"trace_id": "i2349016cd7e8f93g6hh375h6k6k0599"
}
}

Schema Validation Failed

{
"error": {
"message": "Output schema validation failed: $.name: required property missing",
"type": "schema_validation_error",
"code": "schema_validation_failed",
"trace_id": "j3450127de8f9004h7ii486i7l7l1600"
}
}

Context Window Exceeded

{
"error": {
"message": "Estimated token count 150000 exceeds context window 128000 (no pruning strategy configured)",
"type": "context_window_error",
"code": "context_window_exceeded",
"trace_id": "k4561238ef9g0115i8jj597j8m8m2711"
}
}

Failover Blocked

HTTP/1.1 503 Service Unavailable
X-Gateway-Failover-Blocked: capability_mismatch
{
"error": {
"code": "failover_capability_mismatch",
"message": "Failover blocked: no fallback provider supports response_format: json_schema. Primary provider [openai] failed: upstream down"
}
}

Troubleshooting

SymptomLikely CauseFix
400 no_providerAPI key not set for the providerSet the environment variable (e.g., OPENAI_API_KEY)
403 data_residency_violationData residency policy violationConfigure routing to use providers in allowed regions
400 unsupported_response_formatProvider doesn't support the formatUse a different provider or remove response_format
400 no_capable_providerNo provider on the route supports itAdd a capable provider to the route
404 tenant_not_foundTenant ID does not existVerify the tenant ID via GET /v1/admin/tenants
404 route_not_foundRoute ID does not existVerify the route ID via GET /v1/admin/routes
404 route_version_not_foundRoute version does not existCheck version history via GET /v1/admin/routes/\{id\}/versions
404 report_not_foundReport ID does not existVerify the report ID via GET /v1/admin/reports
400 pii_detectedPII found and action is BLOCKRemove PII from request, or change tenant PII action to REDACT or LOG
403 guardrail_blockedInjection/jailbreak/content detectedReview prompt content; change tenant guardrail action to FLAG or LOG
413 input_too_largeRequest exceeds input size limitsReduce message count, message length, or total input tokens; increase tenant limits via metadata
422 schema_validation_failedResponse doesn't match JSON schemaReview the registered schema via GET /v1/admin/schemas and tighten or relax it; the registry does not yet retry on a single failure (maxRetries is reserved for a future correction-prompt flow).
400 context_window_exceededContext window full, no pruningReduce conversation length; configure pruning strategy via tenant metadata (guardrail.context.pruning-strategy)
402 budget_cap_hardHard budget limit exceededWait for next budget period or increase budget via PUT /v1/admin/budgets/\{id\}
400 compliance_not_availableEnterprise license not activeSet DVARA_LICENSE_KEY to a valid enterprise license key
400 invalid_report_typeInvalid report type specifiedUse one of: SOC2, HIPAA, GDPR
400 mcp_not_availableMCP features require enterpriseSet DVARA_LICENSE_KEY to a valid enterprise license key
401 mcp_auth_requiredMissing Bearer token on MCP ProxyInclude Authorization: Bearer gw_<key> header
401 mcp_auth_invalidInvalid API key on MCP ProxyVerify the API key is correct
401 mcp_auth_revokedAPI key revoked on MCP ProxyGenerate a new API key
404 mcp_server_not_foundMCP server ID does not existVerify server ID via GET /v1/admin/mcp/servers
409 mcp_server_duplicateServer ID already exists for tenantUse a different server_id or check existing servers
403 mcp_policy_deniedMCP request denied by policyCheck policy rules via GET /v1/admin/policies. Review mcp_server, mcp_tool, mcp_arg conditions.
503 mcp_server_unavailableMCP server suspended/disabledRe-activate the server via PUT /v1/admin/mcp/servers/\{id\}, or check upstream health via /v1/admin/mcp/servers/\{id\}/health
429 rate_limit_exceededToo many requestsWait for Retry-After seconds, or increase limits
502 provider_errorUpstream provider returned an errorRead the hint in the error message (e.g., "invalid API key", "rate limited"). For 401: check your provider API key env var. For 429: reduce request rate. For 5xx: check the provider's status page. The gateway retries automatically.
503 provider_circuit_openToo many recent provider failuresThe gateway pauses requests to a failing provider to prevent cascading errors. It resolves automatically after a short cooldown. If it persists after restarting: check your provider API key and account status.
503 failover_capability_mismatchPrimary failed, no capable fallbackAdd more providers to the route that support the capability