> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fiveninelabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# internal

> 500 api_error — our fault. Safe to retry with the same Idempotency-Key; a retry never double-bills.

**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](/errors#failures-that-are-not-errors)".

`internal` is also the conservative default of the
[stream-terminal codes](/errors#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

```json theme={null}
{
  "error": {
    "type": "api_error",
    "code": "internal",
    "message": "Internal error. This request is safe to retry.",
    "doc_url": "https://docs.fiveninelabs.com/errors/internal",
    "request_id": "req_3zz65n"
  }
}
```

## 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`](/guides/test-mode) streams a run that ends `error` with the
reservation released.
