# Errors

> One error shape, application/problem+json — every problem type, when you see it and what to do.

**What this is:** the one shape every error has, and the list of types. **When you need it:** writing the `except` / `catch` around any call.

**curl**


```bash
curl -i "$TASKADENCE_API_URL/v1/tasks/T0000000" \
  -H "Authorization: Bearer $TASKADENCE_TOKEN"
```

**Python**


```python
from taskadence import InsufficientScopeError, NotFoundError, TaskadenceError

try:
    tm.tasks.read("T0000000")
except NotFoundError:
    ...
except InsufficientScopeError as exc:
    print("this token needs", exc.required_scope)
except TaskadenceError as exc:
    print(exc.status, exc.type, "— quote request_id", exc.request_id)
```

**tm**


```bash
tm tasks get T0000000
# exit code 1; the problem is printed with its request_id
```

## The shape

Every error is `application/problem+json` ([RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)):

| Field | Type | Meaning |
| --- | --- | --- |
| `type` | string | `about:blank` or a `urn:taskadence:problem:*` identifier |
| `title` | string | e.g. `"Forbidden"` |
| `status` | integer | e.g. `403` |
| `detail` | any | Human-readable explanation (a string; for a 422, the list of validation errors) |
| `instance` | string | e.g. `"/v1/tasks/T123"` |
| `request_id` | string | e.g. `"9b2f1c1e-8c1a-4a53-9f9e-0f5f1f2d7c11"` |
| `errors` (optional) | array | Structured failures: validation errors, or `{loc, msg, allowed}` for a bad parameter |
| `mfa` (optional) | object | On an `mfa-required` problem only: `enrolled` (does the person have an authenticator app set up), `required_for` (`all` or `admins`) and `reason` (`org_policy`: the organization's requirement; `step_up`: this action needs a second step) |

Branch on `status` and `type`. Show `detail` to people. When you ask for help, quote `request_id` — it is also the `X-Request-ID` response header.

## Problem types

| Status | `type` | What happened — and what to do |
| --- | --- | --- |
| any | `about:blank` | A plain HTTP error; the status and `detail` say everything. |
| 422 | `…:validation` | The request body or query did not validate. `errors` lists each failure (`loc`, `msg`, `type`). |
| 400 | `…:invalid-parameter` | A query parameter is outside what the operation accepts; `errors[].allowed` lists the valid values. |
| 412 | `…:precondition-failed` | `If-Match` did not match the resource's current `ETag` - re-read it and retry. |
| 422 | `…:idempotency-key-reused` | This `Idempotency-Key` was first used for a different request (method, path or body). |
| 409 | `…:idempotency-key-in-flight` | The first request with this `Idempotency-Key` has not finished; retry shortly. |
| 400 | `…:idempotency-key-invalid` | `Idempotency-Key` must be 1–255 printable ASCII characters. |
| 429 | `…:rate-limit` | Too many requests with this access token, or a signed-in user, or an address; wait `Retry-After` seconds (`X-RateLimit-*` say where you stand). |
| 500 | `…:internal` | An unexpected server error. Quote `request_id` to support. |
| 401 | `…:token-invalid` | The access token is unknown or malformed (or its principal no longer exists). |
| 401 | `…:token-expired` | The access token is past its `expires_at`; mint a new one. |
| 401 | `…:token-revoked` | The access token was revoked (by its owner, an admin, a rotation, or its service account's deactivation). |
| 403 | `…:insufficient-scope` | The access token does not carry the scope this operation needs (`errors[0].required`; null = not available to tokens). |
| 403 | `…:test-token-read-only` | A `tkd_test_` token can authenticate and read, never write. |
| 403 · 422 | `…:token-policy` | The organization's token policy refuses this token (personal tokens off, expiry required, or past the maximum lifetime). |
| 422 | `…:url-refused` | The webhook URL is refused: not https, carries credentials, or resolves to a private, loopback, link-local, metadata, multicast or reserved address (`errors[0].reason`). |
| 403 · 409 | `…:mfa-required` | The organization requires two-step sign-in and this session signed in with one step. `mfa.enrolled` says whether the person has an authenticator app set up (sign in with it) or must set one up first; `mfa.required_for` is `all` or `admins`. Access tokens are not affected. |
| 403 | `…:email-unverified` | The signed-in person has not confirmed their email address yet. Confirm it from the email that was sent (or ask for a new one), then retry. Access tokens are not affected. |
| 413 | `…:upload-too-large` | The file is over the size limit (`detail` names it): 25 MB for attachments and project files, 2 MB for an avatar. A zip whose contents unpack to over 10 times the limit counts as too large. |
| 415 | `…:upload-type-not-allowed` | The file's type is not allowed (`detail` lists the allowed types). Executables, scripts, HTML, SVG, XML and macro-enabled Office files are never accepted, nor a zip holding one. |
| 415 | `…:upload-type-mismatch` | The file's contents are not what its extension (or its declared content type) says, for example an executable named `.png`, or a `.txt` that is not UTF-8 text. |
| 422 · 503 | `…:upload-rejected` | The malware scan refused the file (422), or could not scan it right now (503: retry later). |

`…:` is `urn:taskadence:problem:`. Match on the identifiers, not on `title` or `detail`; responses from before the rename used `urn:tasksmate:problem:` (see the [changelog](https://docs.taskadence.com/changelog/)).

The Python SDK raises one exception class per type ([Python SDK → Errors](https://docs.taskadence.com/sdks/python/#errors)).

---
Source: https://docs.taskadence.com/guides/errors/
