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

# Errors and limits

> Status codes, body shapes, degraded behavior, and the hard limits.

## The error body

Every JSON error has the same shape. The `error` value is a short English string, for logs, not
for the student.

```json theme={null}
{ "error": "unauthorized" }
```

Show a Turkish message of your own to the student. Do not show the `error` value.

## Status codes

| Status | Where                 | Value of `error` | What to do                                                               |
| ------ | --------------------- | ---------------- | ------------------------------------------------------------------------ |
| `400`  | `POST /api/chat/send` | `empty message`  | The body had no text and no image. Block the send in the user interface. |
| `401`  | any `/api` route      | `unauthorized`   | Refresh the Supabase session once, then retry once.                      |

There is no `403`, no `404` for a valid route, and no `429`. The API has no rate limit today. Do
not depend on that.

## Schema validation errors

A body that breaks the request schema is rejected by the validator, before the route handler runs.
This response has a different shape. `error` is an array of issues, not a string:

```json theme={null}
{
  "success": false,
  "data": { "dailyHours": 40 },
  "error": [
    {
      "code": "too_big",
      "maximum": 16,
      "path": ["dailyHours"],
      "message": "Too big: expected number to be <=16"
    }
  ]
}
```

Parse `error` as a value of unknown shape. Read `success` first: `false` and a `400` status mean a
schema rejection. The messages are English, and they are for the developer. Read
[Profile and onboarding](/guides/profile-and-onboarding) for the field constraints.

## Failures inside the stream

`POST /api/chat/send` returns `4xx` only before the stream starts. After the stream starts, the
status is `200`, and a failure arrives as an SSE `error` event:

```text theme={null}
event: error
data: {"error":"chat failed"}
```

Treat this as a failed turn. Show a retry control, then call `GET /api/chat/history` to
resynchronize. Read [Stream a chat answer](/guides/chat-streaming).

## Degraded, not failed

Several parts of a turn can fail without failing the turn. The student sees a normal answer, with
less context:

| Part                               | On failure                                             |
| ---------------------------------- | ------------------------------------------------------ |
| Retrieval over the coaching corpus | The turn continues with no retrieved context.          |
| The YÖK Atlas tool server          | The turn retries without those tools.                  |
| Tracing and usage logging          | The turn continues. Nothing is reported to the client. |
| Push delivery                      | The message stays in the history.                      |

Only the model stream itself can fail a turn. The client cannot detect a degraded turn, and does
not need to.

## Limits

| Limit                 | Value                        | Where                              |
| --------------------- | ---------------------------- | ---------------------------------- |
| Message length        | 8000 characters              | `message` in `POST /api/chat/send` |
| History window        | 60 messages                  | `GET /api/chat/history`            |
| Model call timeout    | 60 seconds                   | one turn                           |
| Model steps per turn  | 5                            | one turn                           |
| Profile subject lists | 16 items, 64 characters each | `PATCH /api/profile`               |
| Scratchpad notes      | 2000 characters              | internal, model-maintained         |
| Rate limit            | none today                   | —                                  |

Set the client request timeout for `POST /api/chat/send` to at least 90 seconds. A turn with
several tool steps takes longer than a plain answer.

## Retries

<Warning>
  Never retry `POST /api/chat/send` automatically. The student message is persisted before the model
  runs, so an automatic retry duplicates it in the history. Retry only when the student asks for it.
</Warning>

`GET /api/me`, `GET /api/chat/history`, and `GET /health` are read-only, and safe to retry.
`PATCH /api/profile` writes the same values again, so it is also safe to retry.
