Error reference

This page is the canonical envelope reference for the Shroud API: the HTTP status table, the JSON shape every error follows, the request_id and Retry-After semantics callers should observe, and the per-transport notes for HTTP, MCP, JSON-RPC, and the Cocoon WebSocket. For the auto-generated, exhaustive list of structured codes see Error codes. For caller-side action mapping (when to retry, when to surface, when to alert) see Production guide — Error handling map.

Error envelope

Every error response from the gateway carries the same JSON shape on the HTTP path:

{ "error": "human-readable message", "error_code": "SHROUD_UNAUTHORIZED", "details": { "window": "24h", "used_cu_milli": 100000, "limit_cu_milli": 100000 } }

Field

Type

Notes

error

string

Human-readable message. Stable enough for log lines, never parse.

error_code

string

Stable SHROUD_* code. This is the value caller logic should branch on.

details

object (optional)

Structured payload specific to the code. Omitted when there is nothing to add.

Content-Type: application/json is set on every error response, including the 401 and 429 paths that some legacy docs described as "plain text" — the gateway has emitted JSON envelopes since 2025 and no path falls back to plain text. The full code list and per-code HTTP status mapping is in Error codes.

HTTP status table

Status codes used by middleware before reaching the handler:

HTTP

Code

Cause

400

SHROUD_INVALID_PARAMS/SHROUD_SCHEMA_VIOLATION/SHROUD_BATCH_TOO_LARGE/SHROUD_INVALID_IDEMPOTENCY_KEY/SHROUD_WRITE_IN_BATCH

Caller-side validation failure.

401

SHROUD_UNAUTHORIZED

Missing or malformed Authorization header, key not found, environment mismatch, expired key.

403

SHROUD_PERMISSION_DENIED

Authenticated, but the key lacks the capability for this tool.

404

SHROUD_NOT_FOUND/SHROUD_TOOL_NOT_FOUND

Resource or tool name does not exist on this deployment.

409

SHROUD_CONFLICT

Idempotency-Key in flight on a concurrent request, or other state conflict.

410

SHROUD_CONFIRMATION_EXPIRED

Two-step confirmation token expired.

422

SHROUD_IDEMPOTENCY_KEY_MISMATCH

Idempotency-Key reused with a different request body.

429

SHROUD_RATE_LIMITED

Per-key or per-IP request rate exceeded. Retry-After: 1.

429

SHROUD_CU_LIMIT_EXCEEDED

Per-key or workspace Credit Unit budget exhausted. Retry-After: 60.

500

SHROUD_INTERNAL_ERROR/SHROUD_TOOL_EXECUTION_ERROR

Server-side or upstream tool failure.

503

SHROUD_SERVICE_UNAVAILABLE

Upstream dependency briefly unavailable. Retry-After set.

Authentication errors (401)

SHROUD_UNAUTHORIZED is returned with HTTP 401 Unauthorized and the canonical envelope. Common triggers:

{ "error": "missing authorization header", "error_code": "SHROUD_UNAUTHORIZED" }

Trigger

Message

No Authorization header on a protected route

missing authorization header

Header without a Bearer prefix

invalid authorization format

Key whose format does not match shroud_(dev\|stage\|prod)_<32 hex>

invalid authorization format

Key environment does not match the deployment environment

unauthorized

Key not found, revoked, or expired

unauthorized (or api key has expired)

The Bearer prefix is required exactly. Token <key>, lowercase bearer, and the bare key with no prefix are all rejected. See Authentication for the supported header forms and key lifecycle.

Rate limit errors (429)

There are two distinct 429 Too Many Requests paths. Both use the canonical envelope; they differ in error_code, in Retry-After, and in whether details is populated.

Per-key / per-IP RPS (SHROUD_RATE_LIMITED)

{ "error": "too many requests", "error_code": "SHROUD_RATE_LIMITED" }

Retry-After: 1. Returned when the per-key token-bucket trips for authenticated callers, or when an anonymous (no-key) request exceeds 5 RPS for its source IP. See Production guide — Rate limits and CU budgets for the per-plan caps and the anonymous bucket rules.

CU limit (SHROUD_CU_LIMIT_EXCEEDED)

{ "error": "CU limit exceeded", "error_code": "SHROUD_CU_LIMIT_EXCEEDED", "details": { "window": "24h", "used_cu_milli": 100000, "limit_cu_milli": 100000 } }

Retry-After: 60. The same code is used for per-key rolling-window limits and for workspace-wide plan limits; the scope is signalled by the presence of details.window:

Scope

details.window

Other fields

Per-key 24-hour limit

"24h"

used_cu_milli, limit_cu_milli

Per-key 30-day limit

"30d"

used_cu_milli, limit_cu_milli

Workspace plan + purchased balance exhausted

absent

used_cu_milli, limit_cu_milli

used_cu_milli and limit_cu_milli are reported in milli-CU; divide by 1,000 for CU and by 1,000,000,000 for USD. See Billing for the unit definitions.

Retry-After semantics

The gateway sets Retry-After as a hint, not a guarantee. The recommended caller pattern is to honour it as the floor and apply your own jittered exponential backoff on top:

delay = max(retry_after_seconds, base * 2^attempt + random(0, jitter))

Retry-After values currently emitted by the gateway:

Code

Header

SHROUD_RATE_LIMITED

Retry-After: 1

SHROUD_CU_LIMIT_EXCEEDED

Retry-After: 60

SHROUD_SERVICE_UNAVAILABLE

Retry-After: 5 (typical)

When the OpenAI-compatible chat-completions path returns 503 because the upstream Cocoon worker is unavailable, the response body uses OpenAI shape rather than the SHROUD envelope. See OpenAI-compatible API for that special case.

Request correlation

Every request carries a session correlation ID written to the gateway logs. Pass X-Request-Id on the request and the gateway will echo it on the response so client logs and server logs can be joined post-hoc. Always log the request id alongside any non-2xx status — when filing a bug or support ticket the id is the fastest way for the team to find the matching server-side trace.

The MCP transport additionally returns a session id in the Mcp-Session-Id response header on the initialize call. Subsequent requests on the same agent session should echo this header back; see MCP API for the full session lifecycle.

Transport-specific envelopes

The shape above is what HTTP-level callers see. Tool-layer errors emerge through three transports, and each wraps the SHROUD code slightly differently.

HTTP path (OpenAI-compatible / Cocoon SSE shim)

The OpenAI-compatible chat-completions endpoint surfaces upstream inference errors using OpenAI's own shape:

{ "error": { "message": "model not available", "type": "internal_error", "code": "MODEL_NOT_AVAILABLE" } }

This path does not carry a SHROUD_* code. It exists for drop-in OpenAI client compatibility; for the Shroud-native HTTP endpoints (/v1/admin/*, /tma/*) the canonical envelope above applies.

MCP transport (POST /mcp)

MCP returns errors as a tool result with isError: true and the SHROUD code in _meta.errorCode:

{ "content": [ { "type": "text", "text": "tool not found: midnight_nonExistent" } ], "isError": true, "_meta": { "errorCode": "SHROUD_TOOL_NOT_FOUND" } }

JSON-RPC transport (POST /rpc)

The JSON-RPC transport follows the JSON-RPC 2.0 spec: a top-level error object with a numeric code, a human-readable message, and the SHROUD code in error.data.errorCode.

{ "jsonrpc": "2.0", "id": 1, "error": { "code": -32601, "message": "tool not found: midnight_nonExistent", "data": { "errorCode": "SHROUD_TOOL_NOT_FOUND" } } }

The numeric code follows JSON-RPC conventions: -32601 for unknown tool, -32602 for invalid params, -32603 for tool execution failures. Always read the SHROUD code out of error.data.errorCode rather than parsing the numeric code, because the numeric mapping may evolve.

JSON-RPC protocol-level errors

Envelope-level errors emitted before tool dispatch do not carry a SHROUD code in error.data:

Numeric code

Name

Description

-32700

Parse Error

Invalid JSON in request body.

-32600

Invalid Request

Malformed JSON-RPC envelope or missing method.

-32601

Method Not Found

Unknown method, including tools.list/tools.call typos.

Calling midnight_getBlock directly as a JSON-RPC method returns -32601 Method Not Found at the protocol layer. Use tools.call with {"tool": "midnight_getBlock"} instead.

RPC proxy errors (/v1/midnight/rpc)

The Midnight RPC proxy maps whitelist and upstream-node failures to JSON-RPC errors:

Scenario

Numeric code

Name

Method missing or jsonrpc version invalid

-32600

Invalid Request

Method not on the whitelist

-32601

Method Not Allowed

Node unreachable / internal proxy error

-32603

Internal Error

Upstream node returns an RPC error

passthrough

Forwarded from Midnight node

The whitelist is per-deployment. Call midnight_listMethods (MCP tool) or read /.well-known/mcp to see which methods are enabled on the deployment you are targeting; see RPC proxy for details.

Cocoon WebSocket (wss://shroud.us/v1/cocoon/stream)

The encrypted Cocoon WebSocket emits a single error frame on stream failure. The shape is set by the Cocoon protocol, not the SHROUD envelope:

{ "type": "error", "error": "model not available", "code": "MODEL_NOT_AVAILABLE" }

Code

Description

MODEL_NOT_AVAILABLE

Requested model is not active on this network.

(no code)

General error — read error for the message.

The Go SDK surfaces this through stream.Err() and the TS SDK through the rejected promise / StreamError class. See Cocoon SDK (Go) and Cocoon SDK (TypeScript).

SDK-level errors

Go SDK (shroud-sdk-go):

  • stream.Err() returns the error that stopped the stream.

  • Attestation policy failures return errors directly from Inference().

TypeScript SDK (@shroud/cocoon-sdk-js):

Class

Meaning

SessionError

WebSocket connection or session setup failed.

CryptoError

Key derivation, encryption, or decryption failed.

AttestationError

TEE attestation verification failed.

StreamError

Server reported an inference error.

Troubleshooting

401 Unauthorized

  • Verify your API key format: shroud_{env}_{32 hex chars}.

  • Check the environment matches the deployment (don't use shroud_dev_ keys against prod).

  • Verify the key hasn't expired or been revoked in the dashboard.

  • Ensure the Authorization header uses the Bearer prefix (capital B, single space).

429 Too Many Requests

Rate limit (Retry-After: 1):

  • Check your plan's RPS limit (Free = 2, Developer = 10, Startup = 50, Enterprise = 200).

  • Anonymous (no-key) callers hit a 5 RPS per-source-IP cap; send a key on production traffic.

CU limit (Retry-After: 60):

  • Read details.window24h/30d is per-key, absent is workspace-wide.

  • Monitor usage in the dashboard; raise the per-key limit or upgrade the plan.

MCP tool errors

  • SHROUD_TOOL_NOT_FOUND — list the deployment's tools at GET /.well-known/mcp.

  • SHROUD_INVALID_PARAMS/SHROUD_SCHEMA_VIOLATION — compare your payload against the tool's input schema in MCP API.

  • SHROUD_TOOL_EXECUTION_ERROR — upstream Midnight node or model worker error; retry with backoff.

Cocoon attestation failures

  • Make sure you're running the latest SDK with up-to-date image hashes.

  • If you supply a custom AttestationPolicy, double-check the allowed hashes match the deployment.

  • Persistent failures may indicate a TEE upgrade — check for SDK releases.

Last modified: 08 May 2026