Skip to main content
Version: 1.7.0

Error Handling

Runs unlicensed

Available with no license, in the Development posture. A license adds the MCP and A2A planes, production rights and support — not this feature.

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).
  • Console and Portal errors — DVARA Flightdeck on port 8090, serving the Console and the workspace Portal.
  • MCP Gateway errors — served by the gateway on port 8080 alongside /v1/* (the separate MCP process was retired in 1.7.0). 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 when the JSON body is malformed or unparseable.
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 workspace pruning strategy is configured.
400pii_violationpii_detectedPII detected in the request and the workspace policy is BLOCK.
402budget_exceededbudget_cap_hardHard budget cap reached on the workspace or the API key.
402budget_exceededper_call_cost_exceededA single request's estimated cost (max_tokens × output price) exceeded the per-call ceiling, set by dvara.llm-gateway.finops.per-call-max-cost-usd or Workspace.metadata["cost.per-call-max-usd"]. Complements the accumulated-spend cap; off by default.
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 workspace action is BLOCK.
403data_residency_errordata_residency_violationGeo-aware routing found no provider in the workspace's allowed regions.
403ip_access_errorip_access_deniedClient IP blocked by global or per-workspace CIDR rule.
403workspace_credential_requiredworkspace_credential_requiredStrict-BYOK enforcement rejected the call — the workspace has no own active provider credential. Set under dvara.credentials.require-workspace-credential=true (global) or Workspace.metadata["credentials.require-workspace-credential"] (per-workspace). Audit event: PROVIDER_CREDENTIAL_MISSING.
403workspace_suspendedworkspace_suspendedWorkspace administratively suspended — trial-cliff expiry, chronic-abuse sweep, self-delete schedule, or manual operator action. Audit event per blocked request: WORKSPACE_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 workspace's tier is over its concurrency threshold.
429provider_rate_limitedprovider_rate_limitedThe upstream provider credential's published rate-limit budget is exhausted; the gateway shed the request after finding no capable non-shed fallback. Carries a Retry-After header derived from the upstream signal. Requires dvara.llm-gateway.provider-rate-limit.enabled=true.
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.

Console and Portal errors

Emitted by the DVARA Flightdeck on port 8090. Same envelope shape as the data plane, same lowercased-code convention.

These codes moved surface, they did not go away

These codes predate the removal of the Admin API in 1.7.0 and are now raised by the Console and Portal rather than by /v1/admin/**, which returns 404. The codes and their meanings are unchanged.

Authentication and authorization

StatustypecodeWhen
401unauthorized_errorauthentication_requiredAdmin caller missing or invalid Bearer token / PAT / JWT. Emitted on authentication failure.
403forbidden_erroraccess_deniedWorkspace-scope violation: a workspace-role caller (admin / developer / viewer) tried to read or write a resource belonging to another workspace, or a caller lacked the URL-pattern RBAC role required for the path. Emits a WORKSPACE_SCOPE_VIOLATION audit event capturing the path, method, requested workspace 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 when request validation fails.
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 workspace than the caller's RBAC scope allows:

workspace_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_availableNot reachable on a shipped image. The code belongs to a fallback that the real report generator always overrides, because the generator is not licence-gated — measured on 1.7.0, a SOC2 report generates on an unlicensed Development install.
400invalid_request_errorchargeback_not_availableNot reachable on a shipped image, for the same reason as compliance_not_available above — chargeback report generation is not licence-gated either.
400invalid_request_errormcp_not_availableRaised by no-op MCP services where one is still reachable — for example credential rotation from the Console. It is not what an unlicensed install returns for /mcp/**: the plane is not registered at all there, so those paths answer 404 not_found. See the MCP table below.
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 storage_mode is not one of ENCRYPTED / REFERENCE.
400invalid_request_errorcredential_api_key_missingCreating or rotating a credential in the Console with storageMode=ENCRYPTED but no api_key field in the body.
400invalid_request_errorcredential_reference_missingCreating or rotating a credential in the Console with storageMode=REFERENCE but no secret_reference 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 api_key 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 workspace.
409duplicate_erroruser_duplicateUser email already exists for the target workspace.
413payload_too_largemock_scenario_too_largeScenario source exceeded the 256 KB limit.
500admin_errorDefault fall-through for any unmatched gateway-thrown error.

MCP Gateway errors

Emitted by the MCP plane, which runs inside the gateway on port 8080 under /mcp. Almost every error — auth, policy, agentic governance, upstream failure — comes back through the same lowercase-code, type: "mcp_error" envelope. MCP_WORKSPACE_SUSPENDED is the exception and is noted in the table below; a client that keys on type will not recognise it.

{
"error": {
"message": "…",
"type": "mcp_error",
"code": "mcp_server_not_found",
"trace_id": "…"
}
}
StatuscodeWhen
400mcp_not_availableMCP Gateway requires an enterprise license. Measured on 1.7.0, an unlicensed install does not return this for a /mcp/** call — the plane is not registered, so the request answers 404 not_found with the neutral envelope. Treat 404 not_found on every /mcp path as the licence signal, and mcp_not_available as the signal from a no-op MCP service reached through some other surface.
400mcp_pii_detectedPII detected in the tool-call arguments or response, workspace policy is BLOCK.
401mcp_auth_requiredMissing Authorization: Bearer <key> on the MCP Gateway request.
401mcp_auth_invalidAPI key does not resolve to an active workspace.
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_WORKSPACE_SUSPENDEDThe calling workspace is suspended. Since 1.7.0 this stops MCP tool calls and A2A hops as well as LLM requests — McpWorkspaceContextFilter and A2aAuthFilter enforce it on their own planes. This one refusal does not use the envelope above — measured on 1.7.0, it returns {"error":{"message":"Workspace is suspended","code":"MCP_WORKSPACE_SUSPENDED"}}: the code is UPPERCASE, and there is no type and no trace_id. Match on the status and the code, not on type.
403mcp_session_killedThe session has been terminated by the Console; subsequent tool calls for that session return immediately.
404not_found (type not_found_error)Wrong URL under /mcp (e.g. typo, excluded actuator path, bot probe). Measured on 1.7.0 — a path no controller claims is answered with the neutral envelope, not the mcp_error one. Returned when the route or path is unknown 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 workspace.
408mcp_approval_timeoutApproval gate reached its configured timeout with no human decision; workspace 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 Gateway 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 "Authorization: Bearer $DVARA_API_KEY" \
-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"
}
}

Workspace Not Found

{
"error": {
"message": "Workspace not found: t-999",
"type": "not_found_error",
"code": "workspace_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. Workspace 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 workspace_not_foundWorkspace ID does not existVerify the workspace ID via the Console
404 route_not_foundRoute ID does not existVerify the route ID via the Console
404 route_version_not_foundRoute version does not existCheck version history via GET the Console routes/\{id\}/versions
404 report_not_foundReport ID does not existVerify the report ID via the Console
400 pii_detectedPII found and action is BLOCKRemove PII from request, or change workspace PII action to REDACT or LOG
403 guardrail_blockedInjection/jailbreak/content detectedReview prompt content; change workspace guardrail action to FLAG or LOG
413 input_too_largeRequest exceeds input size limitsReduce message count, message length, or total input tokens; increase workspace limits via metadata
422 schema_validation_failedResponse doesn't match JSON schemaReview the registered schema via the Console 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 workspace metadata (guardrail.context.pruning-strategy)
402 budget_cap_hardHard budget limit exceededWait for next budget period or increase budget via PUT the Console 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 GatewayInclude Authorization: Bearer gw_<key> header
401 mcp_auth_invalidInvalid API key on MCP GatewayVerify the API key is correct
401 mcp_auth_revokedAPI key revoked on MCP GatewayGenerate a new API key
404 mcp_server_not_foundMCP server ID does not existVerify server ID via the Console
409 mcp_server_duplicateServer ID already exists for workspaceUse a different server_id or check existing servers
403 mcp_policy_deniedMCP request denied by policyCheck policy rules via the Console. Review mcp_server, mcp_tool, mcp_arg conditions.
503 mcp_server_unavailableMCP server suspended/disabledRe-activate the server via PUT the Console mcp/servers/\{id\}, or check upstream health via the Console 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