Skip to main content
A failed Router call carries its HTTP status, an error bucket in X-Comfy-Error-Type, and a request ID in X-Comfy-Request-Id. Keep all three, and keep the Idempotency-Key you sent, before deciding whether to retry.

Read errors defensively

A failed request can return a proxy’s HTML error page, truncated JSON, or plain text. Do not let a JSON parsing error hide the HTTP status or request ID. These helpers use an httpx.Response in Python and a Fetch Response in TypeScript; the SDKs already expose error fields for normal SDK calls.

Validation errors

A Router 422 means validation failed before the provider call and is not billed. Its body has a detail[] array, with one entry per rejected field. The error category is in X-Comfy-Error-Type, not in the body. For example:
This is an example shape. Models with a permissive input schema may forward a missing field to the provider instead of returning a Router 422. 400 describes a request-level problem, such as a malformed cursor, rather than this per-field validation body. The error reference lists the supported categories. Treat an unknown category as internal_error for control flow, but keep the original value for diagnostics. Do not hard-reject a new error value or implement forecast error categories as though they already occur.

Retry safely

Persist the key with the model ID and request body before sending. Reuse it for every attempt of that logical call. Router does not return the Idempotency-Key to you in its response. The Python SDK includes its key on raised exceptions; in TypeScript, keep your supplied key yourself. Keys are shared within the workspace carried by the credential, or scoped to the user when it carries no workspace. Use a UUID unique across that scope and retry with the same credential. Reusing another workspace member’s key can return their recorded result or a conflict; changing credentials can start a separate, billable call. Router retains keyed response or collection state for 24 hours; a retry does not start a new retention window. Once that state expires, do not expect the old key to recover a result or prevent a new dispatch. A key also does not make an expired asset URL usable again.

Retry outcomes

Conflicts compare the method, model path, query, and body. A key can become non-replayable after an oversized response, failed response write, or an asset that cannot be safely replayed. Waiting does not recover a consumed result. A new key starts a new call; it does not retrieve the old output. A refusal before provider dispatch releases the key. A dispatched call can retain a provider handle or become non-replayable. Do not infer key state or billing from the status code alone. Do not mint a brand-new key just because a call timed out or the connection dropped. If Router already accepted the generation, a new key can create a second logical run and therefore a second billable outcome. Reuse the same key until you know the original call is unrecoverable.

Timeouts and collection

One Router call may hold the connection for 10 minutes by default. Set your client timeout above that bound so you keep the typed 504 and the request ID rather than an opaque local abort. If your application cannot hold a connection that long, queued delivery returns a request_id at once and lets you collect the result later. deadline_exceeded is Router’s waiting limit; provider_timeout is the provider’s deadline. A provider generation that completes can be billed even if the caller received a timeout or disconnected. Client cancellation stops the wait and SDK retries, but does not necessarily cancel accepted provider work. For submit-and-poll providers, a retained handle lets a same-key request continue collecting the original generation. Dispatched calls cut off without a recoverable handle can consume the key without a replayable result; a same-key retry then returns 409. Provider-attributed transient failures without a captured success can still release the key for another attempt. The absence of a handle alone does not tell you which outcome applies. The SDKs retry some failures within a bounded budget. Once they return an error, keep the request and key rather than generating a new one. For raw HTTP, this example retries only the two explicit collection hints:
Pass the original model, body, and saved key. This limits attempts, not total wall time: each call can last up to the client timeout and each wait follows Retry-After. HTTP errors retain the response for inspection; transport errors propagate without replacing the key. Schedule later collection with the saved key if your application needs a longer recovery window.

Next

  • Billing: what a refusal, timeout, or replay costs.
  • Headers: idempotency, request IDs, and retry pacing headers.
  • API reference: every error bucket Router returns.