Skip to content

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.