Gateway Errors¶
Gateway errors are bounded, typed, and safe to log with the response correlation ID. Never log the raw key or request content.
OpenAI-compatible envelope¶
Model routes return:
{
"error": {
"message": "Model request failed",
"type": "invalid_request_error",
"param": null,
"code": "unsupported_feature"
}
}
| Status | Code | Recovery |
|---|---|---|
| 400 | invalid_request |
Correct the strict JSON, model, W3C context, a tool_choice sent without tools, or a governed-tools opt-in (x-mc-* header values, tool_names, rounds outside 1–20, a second mcp tool object). |
| 400 | unsupported_feature |
Remove hosted/stateful/provider-specific fields, stream: true combined with governed tools, or an mcp tool object whose server_label is not mission-control; do not retry unchanged. |
| 400 | governed_tool_conflict |
A function tool of your own has the name of a governed tool (<server-id>__<tool-name>); rename yours or drop the opt-in. |
| 401 | invalid_api_key |
Install a current key or correct the signed service call. |
| 403 | operation_denied |
Correct current key/owner/Team state and operation/resource policy. |
| 400 | capability_unavailable |
Restore an eligible configured deployment and active snapshot, or remove a field the deployment's vendor profile does not accept. |
| 400 | provider_rejected_request |
The provider refused the request as sent and no deployment can help; do not retry unchanged. Captured diagnostic detail is separately permissioned; settings access alone does not grant it. |
| 429 | provider_rate_limited |
Every eligible deployment is rate limited; honor Retry-After (at most 60 seconds), or none when the provider sent none. |
| 503 | provider_account_rejected |
Every eligible deployment's credential or account was refused; an admin corrects the provider credential. |
| 503 | provider_unavailable, provider_response_invalid |
Restore the provider; the outcome is recorded as indeterminate unless the deployment is retry-safe. |
| 503 | service_unavailable |
Restore the active snapshot or local control, evidence, telemetry, or accounting dependency. Check the Trace and provider evidence before retrying. |
| 503 | instance_saturated |
This gateway instance holds its in-flight maximum; nothing was recorded or dispatched. Honor retry-after (1 second); behind a load balancer the retry reaches another instance. |
| 429 | team_share_exceeded |
Your Team holds half of this instance's in-flight maximum; nothing was recorded or dispatched. Honor retry-after (1 second) and spread the burst. |
| 429 | budget_exceeded, unbounded_estimate, usage_unknown |
Honor safe retry timing when provided or review the authorized cap or finite output estimate. |
Model guardrail failures use the same envelope:
| Status | Code | Recovery |
|---|---|---|
| 400 | guardrail_input_blocked |
Review the input policy with an administrator. The blocked input is not sent to the provider. |
| 400 | guardrail_output_blocked |
The provider's output was blocked; provider work may have been billed. Inspect the policy decision before retrying. |
| 503 | guardrail_unavailable |
Restore the configured guardrail/classifier dependency. The protected call fails closed. |
| 503 | guardrail_redaction_failed |
An administrator must correct the redaction failure before protected input can proceed. |
| 503 | guardrail_output_too_large |
Output exceeded the protected stream buffer. Reduce the requested output or have an administrator review its configured bound; provider work may have been billed. |
See Model guardrails for supported operations, stream buffering, capture, and startup behavior. For a short diagnosis path, use Diagnose a failed request.
A governed tool the gateway runs inside a model call (see Governed tools on a model call) does not fail the model request. The hop's own mcp decision records why it was refused or failed; the model receives the fixed text Tool invocation failed (or the connect request of a per-user Connector) with is_error: true, and the response reports the hop under mission_control.executed_tool_calls or as an mcp_call item with error.message set. Tool arguments, results, and upstream detail never enter the error envelope.
Local decision persistence, span completion, and usage-accounting failures never trigger provider fallback. The public envelope keeps the fixed message Model request failed and does not expose raw exception messages, database details, or credentials. A generic failure does not prove that no upstream work occurred: even a successful provider response can be followed by a local failure. A failed evidence write can leave the decision open until stale-decision recovery; it does not guarantee a durable terminal record during an outage.
MCP envelope¶
MCP returns an HTTP status plus JSON-RPC error. Method, name, Origin, protocol, JSON, authentication, Team allowance, key policy, eligibility, Trace, and admission failures occur before upstream dispatch. The envelope never echoes Connector credentials, tool arguments, or hidden scope.
| Status | JSON-RPC code | Meaning and recovery |
|---|---|---|
| 400 | -32700, -32600, or -32602 |
Correct unreadable/invalid JSON-RPC, remove a posted response/batch, or add the required 2026-07-28 request _meta. |
| 400 | -32020 |
A required MCP HTTP header is missing, malformed, or disagrees with the body. Correct the header/body pair. |
| 400 | -32022 |
The requested protocol revision is unsupported. Use only 2026-07-28; no legacy fallback occurs. |
| 401 | -32001 |
Authentication failed; the response carries the WWW-Authenticate bearer challenge with resource_metadata. Sign in from the client, install a current key, or correct the signed call. |
| 403 | -32003 |
Origin or Team state is invalid. Correct the configured origin or lifecycle state. |
| 404 | -32601 |
The method is not part of the served modern surface. |
| 405/415/406 | -32000 |
Use POST, JSON content, and an Accept header listing JSON plus SSE. |
| 429 | -31029 |
Mission Control product limit denial. Honor Retry-After and safe limit data. This application code is outside MCP's reserved -32020–-32099 range; with data.code of team_share_exceeded, your Team holds half the instance's in-flight maximum: honor retry-after (1 second). |
| 503 | -32603 |
Limit enforcement is unavailable; restore the control dependency before retrying. |
| 503 | -32003 |
Gateway is saturated with data.code of instance_saturated: the instance holds its in-flight maximum and nothing was recorded or dispatched. Honor retry-after (1 second). |
| 499 | no body | The caller closed the modern HTTP response; reconcile evidence before retrying a side effect. |
Handler-level authorization, validation, and upstream failures remain JSON-RPC in-band on HTTP 200 (-32003, -32602, or -32603). This preserves hidden-tool non-disclosure: HTTP status alone does not reveal whether a named tool exists.
Upstream authentication failures use HTTP 200 / JSON-RPC -32603, fixed message Connector authentication could not be completed, and allowlisted data.code: connector_auth_required, connector_auth_failed, connector_auth_unavailable, or connector_insufficient_scope. They never become a Mission Control HTTP 401 challenge. An administrator reconnects missing grants, restores provider/keyring/network availability, or reviews configured scopes. Example:
{
"jsonrpc": "2.0",
"id": 7,
"error": {
"code": -32603,
"message": "Connector authentication could not be completed",
"data": { "code": "connector_auth_required" }
}
}
Failed authentication preparation sends no business call. Rejection after a business POST never triggers automatic replay; reconcile uncertain side effects before issuing another call. See Shared MCP OAuth.
A per-user Connector (see Per-user connectors) answers a call from a person who has not connected their own account, or from a service caller without a verified person, with an in-band tool result rather than an error: HTTP 200, result.isError: true, a text content item naming the Connector and the Console page to connect at, and _meta["mission-control/code"] set to connector_user_auth_required alongside mission-control/connectUrl and mission-control/connectorId. The gateway never falls back to a company or discovery credential, and nothing reaches the upstream. A client shows the text or follows the link; after the person connects under My connections, the same call succeeds. Example:
{
"jsonrpc": "2.0",
"id": 8,
"result": {
"content": [
{
"type": "text",
"text": "Connect your Records account in Mission Control to use this tool: https://console.example.test/acme/connections?connector=records"
}
],
"isError": true,
"_meta": {
"mission-control/code": "connector_user_auth_required",
"mission-control/connectUrl": "https://console.example.test/acme/connections?connector=records",
"mission-control/connectorId": "records",
"io.modelcontextprotocol/serverInfo": {
"name": "mission-control-mcp-gateway",
"version": "1.0.0"
}
}
}
}
A rule that blocks a call (see Rules on arguments and results) answers HTTP 200 / JSON-RPC -32603 with the fixed message Tool invocation blocked by policy and data.code: "rule_blocked", whether the block hit the arguments (nothing was dispatched) or the result (the call ran and the result is withheld). The rule id, the pattern and the matched content never enter the envelope; the decision under Observe → Requests names the rule. Example:
{
"jsonrpc": "2.0",
"id": 9,
"error": {
"code": -32603,
"message": "Tool invocation blocked by policy",
"data": { "code": "rule_blocked" }
}
}
An Action tool that needs a person's approval (see Approvals) answers in band like a per-user connect request: HTTP 200, result.isError: true, a text item linking to the approval page, and _meta["mission-control/code"] of approval_required alongside mission-control/approvalId and mission-control/approvalUrl. Nothing is dispatched, and the decision is recorded with error_code: approval_required and the approval id. The identical call (same caller, tool, declared schema and arguments) is the retry: while the approval is pending it receives the same answer, once approved it runs exactly once, after a denial it receives approval_denied with the decider's note for 24 hours, and a retry that lost a race with a concurrent identical call receives approval_consumed. Example:
{
"jsonrpc": "2.0",
"id": 10,
"result": {
"content": [
{
"type": "text",
"text": "This action needs a person's approval in Mission Control before it runs; call it again once it is approved: https://console.example.test/acme/approvals/approval_0f8c7d2e-4b6a-4d0e-9a1b-2c3d4e5f6a7b"
}
],
"isError": true,
"_meta": {
"mission-control/code": "approval_required",
"mission-control/approvalId": "approval_0f8c7d2e-4b6a-4d0e-9a1b-2c3d4e5f6a7b",
"mission-control/approvalUrl": "https://console.example.test/acme/approvals/approval_0f8c7d2e-4b6a-4d0e-9a1b-2c3d4e5f6a7b",
"io.modelcontextprotocol/serverInfo": {
"name": "mission-control-mcp-gateway",
"version": "1.0.0"
}
}
}
}
Unexpected handler failures always use fixed -32603 message Tool invocation failed; raw exception messages, filesystem paths, database details, and secrets are not relayed. An upstream Connector's reserved server identity is replaced by the public gateway identity before result encoding.
Deployment invoke envelope¶
Before SSE begins, deployment invoke returns { "error": { "code", "message" } } with a fixed safe message. Current boundary codes include authentication_failed (401), invalid_request (400), origin_not_allowed/not_authorized (403), deployment_not_available (403/404 or conflict409), execution_conflict/execution_in_progress (409), rate_limited (429), and deployment_unavailable or runtime driver failure (503). Governance budget/customer codes below also apply. After SSE starts, failure is an AG-UI RUN_ERROR, even when HTTP is200. The client must reconcile partial/uncertain delivery rather than assuming nothing ran.
Budget and customer errors¶
Inference errors never disclose numeric ancestor budget constraints. 429 budget_exceeded, unbounded_estimate or usage_unknown requires a permitted cap/estimate correction or reconciliation; unknown is not zero. Other admission infrastructure failures use 503 admission_unavailable. The capacity refusals 503 instance_saturated and 429 team_share_exceeded carry retry-after: 1 and record nothing. Do not repeat possibly dispatched work merely to clear an uncertain result.
Direct customer validation uses 400 invalid_customer_subject, customer_required or invalid_customer; unavailable/unregistered namespace subjects produce 403 customer_not_allowed. A customer label cannot select a namespace, payer or person. Bad inference credentials map to 401 invalid_api_key. Management has a separate safe {error:{code,message}} envelope and current revision conflicts.
Trace and correlation headers¶
Responses include X-Mission-Control-Correlation-Id and, when Trace context was established, traceparent plus X-Mission-Control-Trace-Id. Record them with the time and safe resource label. They are correlation only and must never be replayed as credentials.
OTLP errors¶
The Collector returns standard OTLP failure status; control/storage outages are retryable while invalid identity/input is permanent. Policy drops/truncation do not prove storage via partial success. Authentication and producer scope/input failures are fixed safe categories and do not echo key, signature, Trace/Span content, or attributes. Retry only retryable transport/backpressure failures; correct permanent identity/input failures first.