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

# Errors

> The error envelope, every error code with its HTTP status, and how to use request_id with support.

When a request fails, Financial Data API returns a JSON body with a stable, machine-readable error code and the same request identifier you would get on success. You can branch on `error.code` programmatically and quote `request_id` when you contact support.

This page covers the error envelope, the full code table, the fail-closed behavior on unknown parameters, and how to use the request identifier.

## The error envelope

Errors mirror the success [envelope](/concepts/response-envelope): an `error` object replaces `data`, and the request identifier is preserved at both the top level and inside `error`.

```json theme={"theme":"css-variables"}
{
  "error": {
    "code": "bad_request",
    "message": "Unknown query parameter: 'contry'",
    "request_id": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55",
    "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55",
    "details": {}
  },
  "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55"
}
```

<ResponseField name="error" type="object" required>
  The error payload. Present instead of `data` on any failed request.

  <Expandable title="error fields" defaultOpen={true}>
    <ResponseField name="code" type="string" required>
      A stable, machine-readable code. Branch on this, not on the human-readable message. See the table below.
    </ResponseField>

    <ResponseField name="message" type="string" required>
      A human-readable description of what went wrong. Subject to change. Do not parse it.
    </ResponseField>

    <ResponseField name="request_id" type="string" required>
      The request identifier, for tracing this failure server-side.
    </ResponseField>

    <ResponseField name="requestId" type="string" required>
      The same identifier in camelCase.
    </ResponseField>

    <ResponseField name="details" type="object">
      Optional structured context for the error. For example, a `rate_limited` error carries `required_scope`, `limit`, and `window_seconds`. May be empty.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="requestId" type="string" required>
  The request identifier, repeated at the envelope root. Identical to `error.request_id`.
</ResponseField>

## Error codes

Codes are stable. The HTTP status always matches the code as listed here.

| Code             | HTTP status | Meaning                                                                                                                        |
| ---------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `bad_request`    | 400         | The request was malformed: an invalid value, a missing required field, or an unknown query parameter.                          |
| `unauthorized`   | 401         | No API key was provided, or the key is invalid. Send a valid key via `x-api-key` or `Authorization: Bearer`.                   |
| `forbidden`      | 403         | The key is valid but lacks the scope required for the route (for example, calling an `ops:read` route with a `data:read` key). |
| `not_found`      | 404         | The requested resource does not exist (for example, an unknown entity, observation, or event id).                              |
| `rate_limited`   | 429         | You exceeded the rate limit for your client and scope in the current window. See [Rate limits](/concepts/rate-limits).         |
| `internal_error` | 500         | An unexpected server error. Retry with backoff; if it persists, contact support with the `request_id`.                         |

<Note>
  Branch your error handling on `error.code`, never on the HTTP status alone and never on the `message` string. The code is the part of the contract that is guaranteed stable.
</Note>

## Fail closed on unknown parameters

Financial Data API rejects unknown query parameters rather than silently ignoring them. If you send a parameter the endpoint does not recognize (for example, a typo like `contry` instead of `country`), the request fails with `bad_request` and a `400` status.

This is deliberate. Silently ignoring a misspelled filter would return data that does not match what you asked for, which is worse than a clear error. Fail-closed means a typo surfaces immediately instead of quietly returning the wrong rows.

```bash A typo fails closed (cURL) theme={"theme":"css-variables"}
curl -s "https://api.financialdatapi.com/observations?contry=USA" \
  -H "x-api-key: $FINANCIALDATA_API_KEY"
# -> 400 bad_request: Unknown query parameter: 'contry'
```

<Warning>
  Check parameter spelling against the [OpenAPI spec](https://api.financialdatapi.com/openapi.json) when you get an unexpected `bad_request`. A rejected unknown parameter is the most common cause.
</Warning>

## Handling errors in code

<CodeGroup>
  ```python Python (requests) theme={"theme":"css-variables"}
  import os
  import requests

  resp = requests.get(
      "https://api.financialdatapi.com/observations",
      headers={"x-api-key": os.environ["FINANCIALDATA_API_KEY"]},
      params={"country": "USA", "indicator": "cpi_inflation_yoy"},
  )

  if not resp.ok:
      err = resp.json()["error"]
      print(f"[{err['code']}] {err['message']} (request_id={err['request_id']})")
      # branch on err["code"]: "rate_limited", "unauthorized", "bad_request", ...
  else:
      data = resp.json()["data"]
  ```

  ```typescript TypeScript (fetch) theme={"theme":"css-variables"}
  const res = await fetch(
    "https://api.financialdatapi.com/observations?country=USA&indicator=cpi_inflation_yoy",
    { headers: { "x-api-key": process.env.FINANCIALDATA_API_KEY! } },
  );

  const body = await res.json();
  if (!res.ok) {
    const { code, message, request_id } = body.error;
    console.error(`[${code}] ${message} (request_id=${request_id})`);
    // switch on code to decide whether to retry, re-auth, or fix the request
  } else {
    const data = body.data;
  }
  ```
</CodeGroup>

## Using request\_id with support

Every error response carries a `request_id` (and its `requestId` twin). The value identifies your exact request in the server logs.

When something looks wrong and you reach out for help, include:

* the `request_id` from the failing response,
* the `error.code` you received,
* the full URL you called (with parameters).

That triple lets support locate your request immediately, without guesswork.

<Columns cols={2}>
  <Card title="Rate limits" icon="gauge-high" href="/concepts/rate-limits">
    The 429 body, the limit headers, and backoff guidance.
  </Card>

  <Card title="Response envelope" icon="box" href="/concepts/response-envelope">
    How errors mirror the success envelope.
  </Card>
</Columns>
