# Error handling
Source: https://docs.aden.space/docs/developers/sdk/errors

How the SDK surfaces failures, and how to react to them.
The SDK never throws on non-2xx responses. It returns `{ data, error }` so
you can branch explicitly.

```ts
const { data, error } = await aden.api.v1.tracks({ id: 42 }).get()

if (error) {
    // error.status is the HTTP status code (number)
    // error.value is the parsed JSON body from the server
    switch (error.status) {
        case 401:
            // Token missing or invalid. Prompt re-auth
            break
        case 403:
            // Auth succeeded but scope is insufficient
            break
        case 404:
            // Track doesn't exist or isn't visible to this key
            break
        case 429:
            // Rate-limited: back off and retry
            break
        default:
            throw new Error(`Unexpected: ${error.status}`)
    }
    return
}

use(data)
```

## Shape of errors [#shape-of-errors]

All error bodies follow:

```json
{ "error": "Unauthorized" }
```

The global error handler in `packages/api/src/index.ts` maps unknown errors
to `500 { error: <message> }` and auth failures to `401 { error: "Unauthorized" }`.

## Network errors [#network-errors]

If the request never reaches the server, `error` is populated with
`status: 'FETCH_ERROR'` and `value` is the underlying `Error`. This is a
good place to retry or flip your app to "offline":

```ts
const { data, error } = await aden.api.v1.tracks.get()

if (error?.status === 'FETCH_ERROR') {
    showOfflineBanner()
    return
}
```

## Rate limits [#rate-limits]

`429` responses include standard rate-limit headers:

* `X-RateLimit-Limit`: maximum requests in the window.
* `X-RateLimit-Remaining`: how many you have left.
* `X-RateLimit-Reset`: unix epoch (seconds) when the window resets.

A simple retry helper:

```ts
async function withBackoff<T>(
    fn: () => Promise<{ data: T | null; error: unknown }>,
    attempts = 3
) {
    for (let i = 0; i < attempts; i++) {
        const result = await fn()
        const err = result.error as { status?: number } | null
        if (err?.status !== 429) return result
        await new Promise((r) => setTimeout(r, 2 ** i * 1000))
    }
    throw new Error('Exhausted retries')
}
```