# Limits and errors

WarpSearch has two kinds of limits. **Plan limits** depend on your plan and are not listed here as
numbers, because they change: see the [free tier](pricing.md#free-tier) and [/pricing](/pricing), or
call `GET /v1/usage` to see yours. **Fixed limits** are properties of the engine and are the same on
every plan. This page lists both, then the errors you get when a request breaks one.

## Plan limits

| Limit | What happens when you exceed it |
|---|---|
| Collections | Creating another answers `403 limit_exceeded`. |
| Stored data | Writes are throttled or refused according to your plan. Check usage in the console. |
| Documents and bytes per write request | `413 request_too_large`. Send smaller batches. |
| Hits per search (`limit`) and result window (`offset + limit`) | `422 limit_exceeded`. |
| Facets per request and buckets per facet | `422 limit_exceeded`. A `size` of `-1` is capped at the plan's limit. |
| Query size, clause count and nesting depth | `422 limit_exceeded`. Query size counts filters, variables, facets and sorts as well as the query. |
| Time per request | `504 timeout`. |
| Requests per second and at the same time | `429 rate_limited` or `too_many_concurrent_requests`. |
| Regex and wildcard queries | `403 forbidden` when your plan does not include them. |
| Response size and monthly returned data | Per-response caps apply on the free tier, and returned data is billed beyond the allowance. |
| Exact (brute-force) vector search | Disabled above a vector count on the free tier. |

See [API keys, roles and rate limits](access-control.md) for how rate limits behave and
[Pricing](pricing.md) for the cost side.

## Fixed limits

| Limit | Value |
|---|---|
| Collection name | `^[a-z][a-z0-9_]*$` |
| Collection description | 2000 characters |
| Collection metadata | 16 KB of JSON |
| Field name | ASCII letters, digits and `_`, starting with a letter, no `__`, at most 127 bytes |
| Indexed term length | 255 bytes. Longer keyword values are kept distinct, but pattern queries may not reach the cut-off tail. |
| Vector dimensions | 8192 |
| kNN `num_candidates` | 10000. `k` is bounded by your result window. |
| Date histogram buckets | 5000, and 1024 when the histogram has metrics or nested facets |
| Fuzzy edit distance | 2 |
| `cardinality` `precision_threshold` | 40000 |
| Percentile `compression` | 20 to 1000 |
| Native query variables | Values only: never a field name, never syntax |

## Error format

REST errors from `/v1` follow RFC 9457 problem details, with the content type
`application/problem+json`:

```json
{
  "type": "https://warpsearch.io/docs/errors/limit_exceeded",
  "title": "Unprocessable Entity",
  "status": 422,
  "code": "limit_exceeded",
  "detail": "offset + limit exceeds the result window for your plan",
  "request_id": "7d1c1a3e0f9b4c2e"
}
```

Branch on `code`, show `detail` to a developer, and include `request_id` when you contact
[support](/contact). Responses to calls on the Elasticsearch, OpenSearch and Solr compatible
endpoints use those APIs' own error shapes with the same HTTP status, so existing clients keep
working.

## Error codes

| Status | `code` | Meaning | What to do |
|---|---|---|---|
| `400` | `invalid_request` | Malformed body, unknown request field, or no documents. | Fix the request. |
| `400` | `invalid_collection_name` | The name breaks the naming rule. | Use lowercase letters, digits and `_`, starting with a letter. |
| `400` | `invalid_mapping` | The mapping is malformed or empty, or uses an unsupported type. | Check the [field types](schemas-and-fields.md#field-types). |
| `400` | `invalid_field` | A field name does not exist or is not allowed. | Check the collection's fields with `GET /v1/collections/{c}`. |
| `400` | `query_error` | The query could not be parsed or is invalid. | Read `detail`, which names the position. |
| `400` | `unsupported_feature` | The query uses something WarpSearch does not offer. | See the status notes in [Query languages](query-languages.md) and [Feature status](roadmap-and-status.md). |
| `401` | | Missing or invalid credentials. | Check the key. |
| `403` | `forbidden` | Your role is too low for this call. | Use a key with the role named in `detail`. |
| `403` | `limit_exceeded` | You have reached your plan's collection limit. | Delete a collection or change plan. |
| `403` | `no_organization` | The signed-in user has no active organization. | Pick an organization in the console. |
| `404` | `not_found` | No such collection or document, or you hold no role on it. | Check the name and your key. |
| `409` | `already_exists` | A collection with that name exists. | Choose another name. |
| `413` | `request_too_large` | The request is over the plan's documents or bytes per request. | Split it. |
| `422` | `limit_exceeded` | A plan limit on a search, such as page size, result window, facets or clauses. | Reduce the request, or change plan. |
| `429` | `rate_limited` | Over your request rate. | Wait for `Retry-After`. |
| `429` | `too_many_concurrent_requests` | Too many requests at once. | Retry shortly. |
| `429` | `too_many_auth_failures` | Too many failed authentications from your address. | Fix the credentials. |
| `429` | `resource_exhausted` | The search backend is overloaded. | Retry later with backoff. |
| `499` | `canceled` | The client closed the connection. | |
| `500` | `internal` | Something failed on our side. | Retry, then report the `request_id`. |
| `503` | `warming_up` | The collection is loading after being idle, or waiting for capacity. | Retry after `Retry-After`. |
| `503` | `unavailable` | The search backend is temporarily unavailable. | Retry with backoff. |
| `504` | `timeout` | The request ran past your plan's time limit. | Narrow it with filters or a time range. |

Two codes appear in the body of a write response rather than as the HTTP error: `unknown_field`
(the document uses a field that is not mapped and has no type suffix) and the per-document codes in
`errors`. See [Ingesting documents](ingesting-documents.md#partial-failures).

## Retrying

| Situation | Retry? |
|---|---|
| `429`, `503`, `504` | Yes, with exponential backoff and jitter, honoring `Retry-After`. |
| `500` | Yes, a few times. |
| Network error or timeout on a write | Yes. Writes with ids replace, so repeating them is safe. |
| `400`, `401`, `403`, `404`, `409`, `413`, `422` | No. The same request will fail again until you change something. |

A `413` write is not retried as is: split the batch first. A `422` search is not retried either:
lower the limit, the page depth or the facet size.

## Warnings

Not every problem is an error. When WarpSearch approximates something instead of rejecting it, the
response succeeds and carries a `warnings` array (and a `Warning: 299` header on compatible
endpoints). Examples are a score approximation in a `multi_match`, an analyzer that fell back to
`standard`, a clamped percentile compression or an ignored index setting. Read warnings while you
are developing: they tell you where WarpSearch differs from the engine you are migrating from.

## Common situations

- **`unknown_field` on every document.** The collection has no mapping for your field names and they
  have no type suffix. Create the mapping or rename the fields.
- **`403` on a call that worked yesterday.** The creator of the key may have left the organization,
  or the key's role was lowered. Check `GET /v1/auth/me`.
- **`404` for a collection you just created.** Check which organization the key belongs to: names are
  per organization.
- **`503 warming_up` on the first request of the day.** An idle collection is loading. Retry. Keep-warm
  avoids it; see [Pricing](pricing.md#cold-starts-and-keep-warm).
- **`422` on a histogram.** The span has too many buckets. Use a larger interval or a narrower range.
- **Slow total counts.** Set `track_total` to `false` when you do not show the total.
