# Overview

When SynthEvents refuses a request, it answers with a **real HTTP status code** and a body that names the error by its **code**. Every code is a URL of the form `https://docs.synthevents.io/errors/<slug>`, which leads to the page of that error in this documentation. This page lists them all.

## The Shape of an Error

Every error has the same shape, with the content type `application/json`:

```json
{
  "type": "error",
  "data": {
    "code": "https://docs.synthevents.io/errors/range-in-future",
    "description": "range reaches into the future: expected to on or before now",
    "details": {
      "to": "2030-01-01T00:00:00Z"
    }
  }
}
```

- **`code`** names the error. Its slug, such as `range-in-future`, reads as a statement of the problem. To tell errors apart in your code, use the code, which stays the same.
- **`description`** says what is wrong and what is expected, in lowercase.
- **`details`** locates the problem. A value in it is given as the request gave it, and a field is named by its path from the root of the body, such as `range.from`. If there is nothing to locate, `details` is an empty object.

## How a Request Is Checked

SynthEvents reports **one error at a time**, the first it finds:

1. A request to generate events without a valid token is refused with **`401`**, before its body is read.
2. A body that is too large is refused with **`413`**.
3. A body that is not a JSON object of the expected shape, such as because of an unknown field or a value of the wrong type, is refused with **`400`**.
4. A body that lacks a field is refused with **`400`** before any of its values is judged, in the order `domain`, `scenario`, `range`, `range.from`, `range.to`, `eventCount`, `seed`, and `format`.
5. A value that is not valid is refused with **`422`**, in the same order.
6. If every slot for generating is taken, the request is refused with **`503`**.
7. If the range and the number of events do not fit together, the request is refused with **`422`** once SynthEvents has tried to size the run.

For `read-data-set`, a body that lacks `name` or `format` is refused with **`400`** before either value is judged, and a name that SynthEvents does not offer with **`422`** before a format it does not know.

So if a request has several problems, fix the one SynthEvents reports and send it again.

## Errors of `generate-events`

These errors come from **`POST /api/v1/generate-events`**:

| Status | Code | Description |
|---|---|---|
| `400` | **[`body-malformed`](/docs/synthevents/errors/body-malformed)** | `body is malformed: expected a JSON object with domain, scenario, range, eventCount, seed, and format` |
| `400` | **[`domain-missing`](/docs/synthevents/errors/domain-missing)** | `domain is missing: expected 'courses', 'library', or 'todo'` |
| `400` | **[`scenario-missing`](/docs/synthevents/errors/scenario-missing)** | `scenario is missing: expected a scenario of the domain` |
| `400` | **[`range-missing`](/docs/synthevents/errors/range-missing)** | `range is missing: expected an object with from and to` |
| `400` | **[`range-incomplete`](/docs/synthevents/errors/range-incomplete)** | `range is incomplete: expected from and to` |
| `400` | **[`event-count-missing`](/docs/synthevents/errors/event-count-missing)** | `event count is missing: expected a number of events from 1 to 20000` |
| `400` | **[`seed-missing`](/docs/synthevents/errors/seed-missing)** | `seed is missing: expected 1 to 64 of a-z, 0-9, and -` |
| `400` | **[`format-missing`](/docs/synthevents/errors/format-missing)** | `format is missing: expected 'cloudevents' or 'eventsourcingdb'` |
| `401` | **[`token-missing`](/docs/synthevents/errors/token-missing)** | `token is missing: expected a bearer token in the Authorization header` |
| `401` | **[`token-invalid`](/docs/synthevents/errors/token-invalid)** | `token is invalid: expected a token issued for SynthEvents` |
| `401` | **[`token-expired`](/docs/synthevents/errors/token-expired)** | `token is expired: expected a token that is still valid` |
| `413` | **[`body-too-large`](/docs/synthevents/errors/body-too-large)** | `body is too large: expected at most 65536 bytes` |
| `422` | **[`domain-unknown`](/docs/synthevents/errors/domain-unknown)** | `domain is unknown: expected 'courses', 'library', or 'todo'` |
| `422` | **[`scenario-unknown`](/docs/synthevents/errors/scenario-unknown)** | `scenario is unknown: expected a scenario of the domain` |
| `422` | **[`range-malformed`](/docs/synthevents/errors/range-malformed)** | `range is malformed: expected RFC 3339 with an offset` |
| `422` | **[`range-empty`](/docs/synthevents/errors/range-empty)** | `range is empty: expected from to lie before to` |
| `422` | **[`range-too-early`](/docs/synthevents/errors/range-too-early)** | `range starts too early: expected from on or after 1970-01-01T00:00:00Z` |
| `422` | **[`range-in-future`](/docs/synthevents/errors/range-in-future)** | `range reaches into the future: expected to on or before now` |
| `422` | **[`event-count-too-low`](/docs/synthevents/errors/event-count-too-low)** | `event count is too low: expected at least 1` |
| `422` | **[`event-count-too-high`](/docs/synthevents/errors/event-count-too-high)** | `event count is too high: expected at most 20000` |
| `422` | **[`seed-malformed`](/docs/synthevents/errors/seed-malformed)** | `seed is malformed: expected 1 to 64 of a-z, 0-9, and -` |
| `422` | **[`format-unknown`](/docs/synthevents/errors/format-unknown)** | `format is unknown: expected 'cloudevents' or 'eventsourcingdb'` |
| `422` | **[`range-too-short`](/docs/synthevents/errors/range-too-short)** | `range is too short for the event count: expected a longer range or fewer events` |
| `422` | **[`range-too-long`](/docs/synthevents/errors/range-too-long)** | `range is too long for the event count: expected a shorter range or more events` |
| `500` | **[`generation-failed`](/docs/synthevents/errors/generation-failed)** | `generation failed: this is a fault of SynthEvents, not of the request` |
| `503` | **[`service-busy`](/docs/synthevents/errors/service-busy)** | `service is busy: try again later` |

## Errors of `read-data-set`

These errors come from **`QUERY /api/v1/read-data-set`**, whose body has exactly the fields `name` and `format`:

| Status | Code | Description |
|---|---|---|
| `400` | **[`body-malformed`](/docs/synthevents/errors/body-malformed)** | `body is malformed: expected a JSON object with name and format` |
| `400` | **[`data-set-missing`](/docs/synthevents/errors/data-set-missing)** | `data set is missing: expected the name of a data set that read-domains lists` |
| `400` | **[`format-missing`](/docs/synthevents/errors/format-missing)** | `format is missing: expected 'cloudevents' or 'eventsourcingdb'` |
| `413` | **[`body-too-large`](/docs/synthevents/errors/body-too-large)** | `body is too large: expected at most 65536 bytes` |
| `422` | **[`data-set-unknown`](/docs/synthevents/errors/data-set-unknown)** | `data set is unknown: expected the name of a data set that read-domains lists` |
| `422` | **[`format-unknown`](/docs/synthevents/errors/format-unknown)** | `format is unknown: expected 'cloudevents' or 'eventsourcingdb'` |
| `500` | **[`generation-failed`](/docs/synthevents/errors/generation-failed)** | `generation failed: this is a fault of SynthEvents, not of the request` |

## Errors of `read-domains`

These errors come from **`QUERY /api/v1/read-domains`**, whose body has to be exactly `{}`:

| Status | Code | Description |
|---|---|---|
| `400` | **[`body-malformed`](/docs/synthevents/errors/body-malformed)** | `body is malformed: expected an empty JSON object` |
| `413` | **[`body-too-large`](/docs/synthevents/errors/body-too-large)** | `body is too large: expected at most 65536 bytes` |

## Other Status Codes

A request to a route that does not exist is answered with **`404 Not Found`**, and one with a method that a route does not take with **`405 Method Not Allowed`**. Both come with a body in plain text, without a code. For the routes and their methods, see **[API](/docs/synthevents/api)**.
