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

# Errors

> Every error code the API can return, and what to do about it.

All errors are returned as JSON with a consistent envelope:

```json theme={null}
{
  "error": {
    "code": "case_not_found",
    "message": "No case matched that identifier.",
    "details": { "identifier": "HKCFA_9999_0" }
  }
}
```

| Field | Stable? | Use it for |
| - | - | - |
| `error.code` | Yes | Branching in your code. Codes do not change without a major version bump. |
| `error.message` | No | Logging, surfacing to humans. Wording may change. |
| `error.details` | No | Optional extra context, varies by endpoint. |

Always switch on `error.code`, never on `error.message`.

## Error codes

### `400 Bad Request`

| Code | Meaning | Fix |
| - | - | - |
| `missing_query` | The `q` parameter is missing or empty on `/v1/cases/search`. | Include a non-empty `q`. |
| `query_too_long` | `q` exceeded the 2000-character cap. | Trim the query. |
| `invalid_scope` | `scope` was not one of `all`, `case_name`, `judgment`. | Use one of the three valid values. |
| `invalid_order` | `order` was not `asc` or `desc`. | Use `asc` or `desc`. |
| `invalid_int` | `limit` or `offset` was not an integer. | Send a base-10 integer string. |
| `invalid_range` | `limit` or `offset` was outside its allowed range. `details` echoes `min`/`max`. | Clamp to the documented range. |
| `invalid_court` | `court` contained an unknown HK court code. `details.valid` lists the accepted set. | Use one of the codes from [Identifiers](https://docs.casebyte.ai/guides/identifiers.md#court-codes). |
| `invalid_date` | `start` or `end` was not a real `YYYY-MM-DD` date. | Reformat as `YYYY-MM-DD`. |
| `invalid_date_range` | `start` was after `end`. | Swap them or fix the typo. |
| `pagination_too_deep` | `offset + limit` exceeded 10,000 (the deepest page Elasticsearch will paginate into). | Narrow the search with court / date filters rather than paging deeper. |
| `missing_identifier` | The `:id` path parameter was empty (after URL-decoding and trimming). | Provide a case ID, neutral citation, or action number. |
| `invalid_identifier` | The `:id` path parameter was over 200 characters or contained characters that can't appear in any of the three accepted forms. | Check the identifier format. See [Identifiers](https://docs.casebyte.ai/guides/identifiers.md). |

### `401 Unauthorized`

| Code | Meaning | Fix |
| - | - | - |
| `missing_credentials` | No `Authorization` header, or it doesn't start with `Bearer `. | Include `Authorization: Bearer cb_live_...`. |
| `invalid_credentials` | Token doesn't start with `cb_live_`, or no key matches in our database. | Check your key. Generate a new one if it was lost. |
| `revoked_credentials` | The key existed but has been revoked. | Generate a new key from your [dashboard](https://casebyte.ai/dashboard). |

### `404 Not Found`

| Code | Meaning | Fix |
| - | - | - |
| `case_not_found` | No case matched the identifier. The `error.details.identifier` echoes what you sent. | Double-check the identifier format. See [Identifiers](https://docs.casebyte.ai/guides/identifiers.md). |
| `not_found` | The route doesn't exist. | Check the URL — note that all resource endpoints live under `/v1/`. |

### `429 Too Many Requests`

| Code | Meaning | Fix |
| - | - | - |
| `rate_limited` | You exceeded your per-minute quota. | Back off with exponential delay + jitter. See [Rate limits](https://docs.casebyte.ai/guides/rate-limits.md). |

### `500 Internal Server Error`

| Code | Meaning | Fix |
| - | - | - |
| `internal_error` | Something failed on our side. | Retry with exponential backoff. If it persists, [report it](mailto:support@casebyte.ai) with the response timestamp. |

## Retry strategy

| Status | Retry? | How |
| - | - | - |
| `4xx` (except `429`) | No | Fix the request first. Retrying won't help. |
| `429` | Yes | Exponential backoff with jitter — see below. |
| `500` | Yes | Exponential backoff (1s, 2s, 4s, 8s…). Cap retries at 3–5. |
| Network error / timeout | Yes | Same as `500`. |

A simple, well-behaved retry loop:

```typescript theme={null}
async function callApi(url: string, init: RequestInit, attempt = 0): Promise<Response> {
  const res = await fetch(url, init);
  if ((res.status === 429 || res.status >= 500) && attempt < 4) {
    const baseMs = 2 ** attempt * 1_000;
    const jitterMs = Math.random() * baseMs;
    await new Promise((r) => setTimeout(r, baseMs + jitterMs));
    return callApi(url, init, attempt + 1);
  }
  return res;
}
```

## Common pitfalls

> **I'm getting `case_not_found` for a case I know exists**
>
> The most common cause is the wrong identifier format. Check:
>
> * Did you URL-encode square brackets in a neutral citation? `[2023] HKCFA 5` must be sent as `%5B2023%5D%20HKCFA%205`.
> * Did you URL-encode the slash in an action number? `FACV 5/2022` must be sent as `FACV%205%2F2022`. The space is optional — `FACV5%2F2022` resolves to the same case.
> * Is the case ID in canonical form? Case IDs are `COURT_YEAR_NUM` (e.g. `HKCFA_2023_5`). Anything with extra trailing segments will not match.
>
> See [Identifiers](https://docs.casebyte.ai/guides/identifiers.md).

> **My boolean query is being treated as plain text**
>
> Boolean operators must be **uppercase** with whitespace around them. `tort and breach` searches for the literal words tort, and, breach. `tort AND breach` is a boolean query. See [Search syntax](https://docs.casebyte.ai/guides/search-syntax.md).

> **I keep getting `429` even though I'm only making a few requests**
>
> The limit is **per API key**, not per IP. If you have multiple processes sharing the same key (e.g. a worker pool), they share the budget. Issue separate keys per worker if you need to parallelise.

> **Search returns 0 results for a query I expect to match**
>
> Try in this order:
>
> 1. Drop court / date filters and search the whole corpus.
> 2. Switch from a phrase (`"..."`) to a plain match query.
> 3. If the case name is uncommon, try `scope=case_name` (fuzzy match enabled).
> 4. Check `start` / `end` — dates outside the corpus return 0.

## Daily summary errors

| Status | Code | Meaning |
| - | - | - |
| 400 | `invalid_query` | Unknown or repeated query parameter. |
| 400 | `date_out_of_window` | The requested day is outside today and the preceding six HKT calendar days. |
| 400 | `invalid_area_of_law` | Unknown Daily label; use `error.details.allowed`. |
| 404 | `summary_not_found` | No completed non-empty summary matched the identifier within the active window. |

Daily also uses `invalid_date`, `invalid_int`, `invalid_range` and
`invalid_identifier`, plus the shared authentication and rate-limit errors.
See [Daily summaries](https://docs.casebyte.ai/guides/daily-summaries.md) for exact date semantics.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.