# Faults

A fault is raised by the runtime when something outside your code goes
wrong. Faults are never declared, listed in `fails`, rejected or matched.
A fault goes straight to the edge of the app, where the client gets a
fixed code and the cause is logged:

| Condition | The client sees |
|---|---|
| The request body is not valid JSON | 400 `invalid_request` |
| Request input breaks a rule | 422 `invalid_input` |
| The route's deadline passed | 504 `deadline_exceeded` |
| Storage failed before anything was committed | 503 `transaction_unavailable` or `read_unavailable` |
| A write may have committed | 500 `outcome_unknown` |
| `Int` overflow, the recursion limit, any defect | 500 `internal_fault` |

## Reacting to a provider's problem

Code that must react to a dependency's problem gets a domain failure from
the place the problem arises. An integration maps the provider's
conditions to failures you declare ([Calling](calling.md)):

```jadpo
failures: {
    provider.invalid_recipient: ReminderRejected
    provider.rate_limited: ReminderDelayed
}
```

The action then lists only those domain failures, never `unavailable` or
`outcome_unknown`:

```jadpo
action send_reminder(todo: Todo) fails ReminderRejected, ReminderDelayed -> Receipt {
    return attempt mail.send_reminder(todo)
}
```

## Defects

A runtime fault that comes from your code is a defect. `Int` overflow and
the recursion limit ([Recursion](recursion.md)) end the operation
with `internal_fault`, undo its writes, and log which one happened:

```json
{
  "event": "operation.failed",
  "classification": "int_overflow",
  "operation": "action:price_line",
  "site": "domains/ordering/actions/price_line.jadpo:4",
  "request_id": "req_0b1e…"
}
```

Division by zero can't happen, because a divisor's type must exclude zero
([Expressions and operators](expressions-and-operators.md)). A
construction that fails at run time never reaches the client as a fault
either, because it needs an `attempt`.

## A bug in Jadpo

A defect the checker should have ruled out is a bug in Jadpo, not in your
app. The client gets the same `500 internal_fault` as for any defect, and
nothing about Jadpo, the version or the cause is in the response. The
operator's `operation.failed` line adds `bug_in_jadpo: true` and `report`,
the address of the issue form, beside the build's version, the
`request_id` and the `.jadpo` frames. It never holds a request body, a
header or a setting value. A fault that is your own code's, such as an
overflow, has `bug_in_jadpo: false` and `report: null`.

The `jadpo` command, `jadpo dev` and `jadpo test` aren't deployed apps. A
panic in them prints a screen that says it is a bug in Jadpo and writes a
crash file for you to read and attach to a report ([When Jadpo itself
fails](14-tooling.md#when-jadpo-itself-fails)). Jadpo sends nothing
anywhere.
