# 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 "$TASKSMATE_API_URL/v1/tasks/T0000000" \
  -H "Authorization: Bearer $TASKSMATE_TOKEN"
```

**Python**


```python
from tasksmate import InsufficientScopeError, NotFoundError, TasksMateError

try:
    tm.tasks.read("T0000000")
except NotFoundError:
    ...
except InsufficientScopeError as exc:
    print("this token needs", exc.required_scope)
except TasksMateError 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:tasksmate: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 |

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; 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 `tm_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`). |

`…:` is `urn:tasksmate:problem:`. The identifiers never change; match on them, not on `title` or `detail`.

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

---
Source: https://developers.tasksmate.indrasol.com/guides/errors/
