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

# Error Handling

> Handle API errors gracefully with the Law4Devs TypeScript SDK.

## Exception hierarchy

All errors thrown by the SDK extend `Law4DevsError`, which itself extends the built-in `Error`. Use `instanceof` checks to handle specific error types.

```
Law4DevsError
├── NotFoundError     (HTTP 404)
├── ValidationError   (HTTP 422)
├── RateLimitError    (HTTP 429)
└── ServerError       (HTTP 5xx)
```

Every error class exposes a `statusCode` property with the underlying HTTP status code.

```typescript theme={null}
import {
  Law4DevsError,
  NotFoundError,
  ValidationError,
  RateLimitError,
  ServerError,
} from 'law4devs';
```

***

## Basic try/catch

```typescript theme={null}
try {
  const article = await client.articles.get('gdpr', 999);
  console.log(article.title);
} catch (err) {
  if (err instanceof NotFoundError) {
    console.error(`Not found (${err.statusCode}): ${err.message}`);
  } else if (err instanceof ValidationError) {
    console.error(`Invalid request (${err.statusCode}): ${err.message}`);
  } else if (err instanceof RateLimitError) {
    console.error(`Rate limited (${err.statusCode}) — all retries exhausted`);
  } else if (err instanceof ServerError) {
    console.error(`Server error (${err.statusCode}) — all retries exhausted`);
  } else if (err instanceof Law4DevsError) {
    console.error(`API error (${err.statusCode}): ${err.message}`);
  } else {
    throw err; // network error or unexpected — re-throw
  }
}
```

***

## Auto-retry behaviour

The SDK automatically retries on `RateLimitError` (429) and `ServerError` (5xx) using exponential backoff with jitter. Only after all retries are exhausted is the error thrown to your code.

```typescript theme={null}
// Configure retry behaviour at construction time
const client = new Law4DevsClient({
  maxRetries: 3,    // default: 3 — set to 0 to disable retries
  timeout: 30000,   // ms — each individual attempt has this timeout
});
```

Timeouts are enforced via `AbortController`, so they apply per-attempt (not across all retries combined).

<Note>
  `NotFoundError` and `ValidationError` are never retried — they indicate client-side issues that will not resolve on retry.
</Note>

***

## TypeScript narrowing with a typed helper

Define a `safeGet` helper to return a typed result or a structured error without propagating exceptions:

```typescript theme={null}
import { Law4DevsClient, NotFoundError, Law4DevsError, Article } from 'law4devs';

type Result<T> =
  | { ok: true; value: T }
  | { ok: false; error: Law4DevsError };

async function safeGet<T>(fn: () => Promise<T>): Promise<Result<T>> {
  try {
    return { ok: true, value: await fn() };
  } catch (err) {
    if (err instanceof Law4DevsError) {
      return { ok: false, error: err };
    }
    throw err; // unexpected — re-throw
  }
}

// Usage
const result = await safeGet(() => client.articles.get('gdpr', 5));

if (result.ok) {
  console.log(result.value.title); // TypeScript knows result.value is Article
} else {
  if (result.error instanceof NotFoundError) {
    console.log('Article does not exist');
  } else {
    console.error(`Unexpected error: ${result.error.message}`);
  }
}
```

***

## Handling errors inside `for await`

Errors thrown during `iter()` or `iterDeadlines()` are propagated out of the `for await` loop. Wrap the loop in try/catch to handle them:

```typescript theme={null}
try {
  for await (const article of client.articles.iter('gdpr')) {
    console.log(article.title);
  }
} catch (err) {
  if (err instanceof RateLimitError) {
    console.error('Rate limit hit during iteration — consider reducing perPage or adding delays');
  } else {
    throw err;
  }
}
```

***

## Error reference

| Class             | HTTP Status | When thrown                       | Retried? |
| ----------------- | ----------- | --------------------------------- | -------- |
| `NotFoundError`   | 404         | Requested resource does not exist | No       |
| `ValidationError` | 422         | Invalid parameters or query       | No       |
| `RateLimitError`  | 429         | Too many requests                 | Yes      |
| `ServerError`     | 5xx         | Server-side error                 | Yes      |
| `Law4DevsError`   | any         | Base class — catch-all            | Depends  |

<Warning>
  After all retries are exhausted, `RateLimitError` and `ServerError` are thrown normally. Always include these in your catch blocks for production code.
</Warning>
