# Errors

> Status codes, the error body, and where per-source failures are reported

Request problems use HTTP status codes and an error body. Data source and data
function problems appear inside `status` in an HTTP `200` response.

## Error body

FastAPI errors use one `detail` key.

```json
{ "detail": "Access token required" }
```

Validation failures use an array.

```json
{
  "detail": [
    {
      "type": "literal_error",
      "loc": ["body", "config", "context"],
      "msg": "Input should be 'prod', 'test' or 'dev'",
      "input": "production"
    }
  ]
}
```

| Field | Type | Description |
| --- | --- | --- |
| `detail` | string or array | Message or validation errors |
| `detail[].type` | string | Failed validation rule |
| `detail[].loc` | array | Field path beginning with `body` |
| `detail[].msg` | string | Human-readable explanation |
| `detail[].input` | any | Rejected value |

`detail[].input` echoes submitted data. Inspect it before forwarding the error.
There is no stable error code or request ID. Branch on HTTP status and, for
`422`, `detail[].loc`; do not parse `msg`.

## Status codes

| Status | When | Retry guidance |
| --- | --- | --- |
| `200` | Request ran; individual work may fail | Read `status` |
| `401` | Token or workflow rejected | Fix credentials |
| `404` | Path does not exist | Fix URL |
| `405` | Method is wrong | Use documented method |
| `422` | Request schema failed | Fix fields in `detail` |
| `500` | Valid request could not process | Retry once with backoff |

There is no service-level `429` or rate-limit header.

> **Confirmation needed:** Confirm whether clients can receive `429`, `502`,
> `503`, or `504` responses and publish retry guidance if so.

## 401 Unauthorized

`Access token required` means no credential was found. `Authentication failed`
means the token, workflow, or pairing was rejected.

## 422 Unprocessable Entity

| Cause | `detail[].loc` |
| --- | --- |
| Missing `config` | `["body", "config"]` |
| Invalid context | `["body", "config", "context"]` |
| Non-object sources | `["body", "config", "sources"]` |
| Non-object inputs | `["body", "inputs"]` |
| Invalid JSON | `["body"]` |

## 500 Internal Server Error

```json
{ "detail": "Internal Server Error" }
```

An empty or missing `/data` `config.sources` currently returns `500`. Always
send at least one source.

> **Confirmation needed:** Empty sources should likely return `422`. Confirm
> whether the service will change before clients depend on the current `500`.

## Failures inside HTTP 200

`/data` status has `success`, `message`, `match`, and `response_time_ms`.
`/func` has all except `match`.

| Message prefix | Endpoint | Cause |
| --- | --- | --- |
| `Adapter not found for` | `/data` | Unknown source |
| `Adapter error:` | `/data` | Credential, vendor, timeout, or input error |
| `Data function not found:` | `/func` | Unknown function |
| `Data function error:` | `/func` | Function raised an error |
| `Unexpected error:` | Both | Result collection failed |

## Client handling

A data function can call several configured data sources. If one of those
sources returns an error, Data Serve normally still returns HTTP `200` because
the service accepted and ran the function request. Clients must inspect the
response body for the function's source-specific errors rather than relying on
the HTTP status alone.

1. Treat non-`200` as a request problem and record `detail`.
2. On `200`, read `status` before `outputs`.
3. Treat `success: true, match: false` as valid no-data.
4. Retry only timeouts and vendor 5xx failures, only for failed sources.
5. Record `transaction_id` from every successful response.
