Format run model 400 invalid_request: unknown id or closed catalog

A model Sume cannot admit on a Format run is a 400, not a silent swap. The order ids are checked in, and why a real Claude id can still fail in your workspace.

5 min readSume
All posts

A Format run whose model Sume cannot admit fails with 400 invalid_request before anything is spent. Two different causes produce it: the id is not in the Agents catalog at all, or it is a real catalog id whose gate is closed in your environment. In neither case does Sume swap in another model.

In what order does Sume check a model id?

The registry's resolver, which the Format create path uses, works in a fixed order. The docs describe the outcome, an id outside the catalog is 400 invalid_request, and the code gives the steps:

  • The comment on the resolver says the same in words: a silent downgrade is how a user ends up billed for something they did not choose, so unknown ids and closed gates fail closed.
  • Step 3 is the only place a string can mean something other than what it says: a Cursor-era id is accepted and runs GPT-6 Sol.
Model resolution on a Format create call (Sume registry; docs read 2026-10-02)
StepInputResult
1Omitted or emptyThe default for the surface; on a Format run that is gpt-6.1-sol
2Not a stringRefused
3An old Cursor-era id such as grok-4.5Resolved to gpt-6-sol
4Any spelling of a catalog rowNormalized to the row's id and moved through its unconditional retirement
5Row retired with a gated successorThe successor, where that id is admitted
6Admission by the row's gateAdmitted, or refused as 400
7No row at allRefused as 400

Why would a valid Claude or Grok id fail?

Because "in the catalog" and "listed in your workspace" are different. Sume gates rows by environment. Opus 5.5, GPT-6 Sol and GPT-6.1 Sol are listed on every catalog, while Sonnet 5.5, Haiku 4.5, GPT-6 Luna and the DeepSeek rows depend on an OpenRouter catalog flag, and Grok 4.7 depends on a Grok flag. A request for a gated row where the flag is closed is a 400, not a move onto a GPT.

So the same payload can pass in one environment and fail in another. The check is cheap: open the Agents model picker in the workspace that owns your key and see whether the id is listed, before you ship it.

How do I handle the error in code?

Treat the 400 as a configuration error, not a retryable one. The errors page lists invalid_request with the other causes, such as a body naming none of instruction, input, previous_run_id or attachments, so branch on the message and not just the code.

Do not auto-retry with a different model string. If you want a fallback, make it an explicit second request that you log, so a cost report never shows a model you did not decide on.

What does a failed create call cost?

Nothing. The model is resolved before the runner is provisioned and before anything is spent, which is why the 400 comes back immediately and why your balance and generation_spend_cap_usd are untouched. A bad model string is therefore a cheap mistake, as long as you read the response instead of retrying it in a loop.

Pair this with an Idempotency-Key on every create, as the docs require. A corrected request is a new body, so it needs a new key, or you will hit a conflict instead of a run.

What about retired ids that moved?

Those do not fail. gpt-5.6-sol runs on gpt-6-sol, Sonnet 5 runs on Sonnet 5.5 and Opus 5 on Opus 5.5, all by design. Unconditional means unconditional: they succeed in an environment where the original was never listed, as long as the successor is admitted. Read model on the receipt, documented in Runs and results, to see where each landed, and see the Sonnet 5.5 id post for the spellings.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume