Skip to main content
HTTP 500 · type api_error. Something failed on our side before a run could start. This is our fault, not your request’s. The money contract still holds: if a reservation was written before the failure, it is settled or released from the durable record — the reaper reconciles any orphaned reservation, so a crashed request can never pin your balance indefinitely. If a run did start and then died, that reaches you as status error on the run (a $0-beyond- receipts outcome, stated), not as this HTTP error — see “Failures that are NOT errors”. internal is also the conservative default of the stream-terminal codes: a run that died in a way we could not classify ends its stream with { "phase": "error", "code": "internal" } — a stream code on a started run, not this HTTP error. Handle unknown stream codes the same way.

The shape

How to fix

  • Retry with the same Idempotency-Key. That’s the designed recovery: if the original actually went through, the retry replays it (fn-idempotent-replay: true) instead of double-billing; if it didn’t, the retry runs it. Use backoff; give up after a few attempts.
  • If it persists, save request_id and contact support — the id joins directly to our gateway logs and, where a run started, to the session record.
  • Check whether a run was created despite the error: GET /v1/sessions?limit=5.

Reproduce it

You can’t provoke this one on purpose, and there is deliberately no test sentinel for it — a 500 is our bug, not an API behavior to rehearse. Rehearse the run-level failure ending instead, which is the one your code should handle deliberately: FN_TEST_ERROR streams a run that ends error with the reservation released.