Errors and refusals

The typed refusals the runtime raises, their stable codes, and how the HTTP handler maps them.

The runtime refuses in a small number of typed ways. Each carries a stable code so a host can match it structurally, and @intentface/latch-server maps every one on every run-producing route (a message, an approval decision, a client-tool result).

StatuscodeClassMeaningWhat the client does
400invalid_messageInvalidMessageErrorThe chat message isn't one a person can send: another role, a part other than text or a file, an id already in the chat, or inline files over maxInlineFileBytes. Nothing was persisted.Send a new user message; send large files by URL.
409rewind_not_supportedRewindNotSupportedErrorAn earlier question was regenerated or edited. Only the last question can be changed in place, because later messages (and what the agent did since) build on it.Fork the chat at that question, or regenerate the last one instead.
409pending_approvalPendingApprovalErrorA decision is outstanding on this chat.Render the approval; resolve it first.
409chat_busyChatBusyErrorA turn is already running in this chat — two tabs, a retry racing a reply, a brief landing mid-conversation. Nothing was persisted.Wait Retry-After (also retryAfterMs in the body), resend the same message.
409chat_conflictChatConflictErrorThe client-chosen chat id exists and isn't the caller's.Pick another id.
429limit_exceededLimitExceededErrorA turn, token or cost budget is spent. retryAfterMs is when the window turns over.Wait Retry-After; tell the user which budget (message).

Structural checks are exported from core: isChatBusyError, isLimitExceededError, isInvalidMessageError; @intentface/latch-channels adds isPendingApprovalError and isChatBusyError for hosts that only see the runtime through its ChannelRunOps view.

What is not an error

  • A denied approval is an answer: the turn resumes and the agent says what it will do instead.
  • A parked unattended run (status: "awaiting_input", trigger: "schedule") is a legitimate outcome — see Run agents on a schedule.
  • An empty 200 from a decision route means the turn cannot resume yet because another gate in the same step is undecided.