Skip to main content

Error Handling

send-message validates every candidate model before it starts a generation run. If at least one candidate survives, you get 200 and generation proceeds with the survivors. If none do, you get 400 in the HTTP response itself — no run is started, and nothing is written to the real-time stream.

POST /api/v1/llm/gateway/send-message   (model: "invalid/model-xyz")

Validate candidates → none survive

400 with an RpcError body

No generation run. No stream update.

This means a 400 here is final. There is no later event to wait for, so a client should surface the error straight away rather than attaching a stream listener.

Handling the response

ResponseWhat it meansWhat to do
200 with a runIdAt least one candidate survivedListen to the stream, or poll conversation-state, as usual
400 MODEL_FILTERED_OUTNo candidate survivedShow the error. Do not listen to the stream — nothing will arrive.

Candidates that fail while others survive are dropped silently: you get 200, and generation runs with what is left. Only the all-or-nothing case surfaces an error.

Error payload

When pre-validation leaves zero candidates, the response body is:

{
"code": "ERROR_CODE_INVALID_ARGUMENT",
"message": "all candidate models were filtered out: [invalid/model-xyz deprecated/old-model]",
"is_terminal": true,
"details": {
"error_info": {
"reason": "MODEL_FILTERED_OUT",
"domain": "conversation"
}
}
}

The payload is identical whether the candidates were rejected as unknown model IDs or eliminated by model_routing_filter — it does not distinguish the two. Either way it is a terminal configuration error: correct the model IDs, or relax the filter.

send-message-sync returns the same shape under the same conditions.

A different payload arrives from generation failures

The error above comes from the conversation actor, synchronously, before generation begins. An error raised later by the generation workflow — for example when the OpenRouter service re-validates candidates during a retry — is streamed instead, and uses code: ERROR_CODE_MODEL_INVALID, reason: "ALL_MODELS_FILTERED", domain: "openrouter", with per-model reasons in message.