---
title: Errors
url: /docs/developers/errors
---

# Errors

The API says what went wrong in two ways. A request it can't take at all gets an HTTP error with a JSON body whose `detail` says why. A call it takes always answers with a receipt, and a receipt that isn't `applied` carries `diagnostics`.

## Errors before a call runs

| HTTP | `detail` | What to do |
|---|---|---|
| 400 | `catalogue cursor is invalid` | The catalogue changed or the cursor is older than 15 minutes. Start again from the first page. |
| 400 | `request body is not valid JSON` | Send a JSON object. |
| 401 | `a bearer credential is required`, `API key not recognised`, `API key revoked`, `API key expired`, `API key no longer carries any authority` | Send a working key ([Authentication](authentication.md)). The answer also has a `WWW-Authenticate: Bearer` header. |
| 403 | `this key is not for this profile` | The key belongs to another business. Use that business's address, or a key made here. |
| 404 | `not found` | No such catalogue entry for this key, or no change this key made with that `operationId`. |
| 413 | `request body is too large` | Keep the body under 64 KB. |
| 415 | `request body must be application/json` | Send `Content-Type: application/json`, in UTF-8. |
| 429 | `too many requests`, `too many changes in progress` | Wait the seconds the `Retry-After` header gives, then send it again ([Limits](limits.md)). |
| 503 | `external access is not available` | GrowLocal can't check the limits right now, so it lets nothing through. Wait and try again. |
| 503 | `operation schemas are not available` | `GET /catalog/{entryRef}` couldn't load the schemas. Try again later. |

## Receipts that aren't applied

A call that runs answers with a receipt ([Make a call and read the receipt](calls-and-receipts.md)). One that is `rejected`, `conflict` or `uncertain` lists what happened in `diagnostics`:

```json title="Receipt"
{
  "status": "rejected",
  "operationId": "change-quote-request-1",
  "diagnostics": [
    {
      "code": "DATA.FIELD_UNKNOWN",
      "stage": "validation",
      "severity": "error",
      "path": "/values/f_nope",
      "message": "column is not declared by this table",
      "repairBy": "caller"
    }
  ]
}
```

`code` is stable, so your software can act on it; `message` is for people. `path` points into what you sent. `repairBy` says who can fix it: `caller` is you; another value, such as `profile-administrator`, means someone in the business must change something first.

A `rejected` receipt answers `400`, or `403` when it's a matter of access (a diagnostic whose `stage` is `authority`).

## Codes you're likely to see

| Code | Status | What it means |
|---|---|---|
| `ACCESS.OPERATION_UNPUBLISHED` | `rejected` (403) | The `target` names an operation the API doesn't offer. Copy it from `GET /catalog`. |
| `ACCESS.KEY_SCOPE_DENIED` | `rejected` (403) | This key wasn't made with access to that operation. |
| `ACCESS.OPERATION_ID_TOO_LONG` | `rejected` (400) | `operationId` is longer than 80 characters. |
| `CONTRACT.INPUT_INVALID` | `rejected` (400) | `input` doesn't match the operation's input; `message` names the field, for example `/query/pageSize 500 is greater than the maximum of 200`. |
| `DATA.RESOURCE_NOT_FOUND` | `rejected` (400) | No such table (or Data feature) here for this key. Get `resourceRef` and `target` from the catalogue and [List data tables](reference/data-tables-query.md). |
| `DATA.FIELD_UNKNOWN` | `rejected` (400) | The table has no field with that id. |
| `DATA.FIELD_MANAGED` | `rejected` (400) | That field is written only by GrowLocal's own step for it (a status, for example), never by a change. |
| `DATA.CURSOR_INVALID` | `rejected` (400) | The row cursor isn't one, or belongs to another query ([Pagination](pagination.md)). |
| `DATA.REVISION_CONFLICT` | `conflict` (409) | The row changed since you read it. Read it again and use its new revision. |
| `DATA.OPERATION_REPLAY_MISMATCH` | `conflict` (409) | This `operationId` was already used with a different body. Use a new one. |
