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

# Error handling

> Handle errors gracefully when using the Layers SDK with the tagged error model, retry strategies, and recommended UX patterns for network failures.

The SDK uses a Result pattern for error handling. All methods return `Result<T, E>` rather than throwing exceptions.

## Result pattern

```typescript theme={null}
const result = await collection.execute()

if (result.error) {
  switch (result.error._tag) {
    case 'NetworkError':
      // Connection issues, timeouts, aborted requests
      console.log(result.error.code) // 'TIMEOUT' | 'CONNECTION_FAILED' | 'ABORTED' | ...
      break
    case 'ApiError':
      // Server errors, rate limits
      console.log(result.error.source) // 'layers' | 'storefront'
      console.log(result.error.status) // HTTP status code
      break
    case 'ValidationError':
      // Invalid parameters
      console.log(result.error.operation) // which method failed
      console.log(result.error.fields) // [{ field, code, message }]
      break
    case 'ConfigError':
      // SDK configuration issues
      console.log(result.error.field) // which config field
      break
  }
} else {
  const data = result.data
}
```

## Error types

All errors have a `_tag` property for type discrimination.

### NetworkError

Connection failures, timeouts, and aborted requests.

| Field          | Type               | Description                                                                     |
| -------------- | ------------------ | ------------------------------------------------------------------------------- |
| `code`         | `NetworkErrorCode` | `TIMEOUT`, `CONNECTION_FAILED`, `DNS_FAILED`, `SSL_ERROR`, `ABORTED`, `OFFLINE` |
| `message`      | `string`           | Human-readable description                                                      |
| `retryable`    | `boolean`          | Whether the request can be retried                                              |
| `retryAfterMs` | `number?`          | Suggested retry delay in milliseconds                                           |

### ApiError

Server errors, rate limits, and GraphQL errors.

| Field          | Type           | Description                                        |
| -------------- | -------------- | -------------------------------------------------- |
| `code`         | `ApiErrorCode` | `NOT_FOUND`, `RATE_LIMITED`, `GRAPHQL_ERROR`, etc. |
| `source`       | `ApiSource`    | `'layers'` or `'storefront'`                       |
| `status`       | `number?`      | HTTP status code                                   |
| `retryable`    | `boolean`      | Whether the request can be retried                 |
| `retryAfterMs` | `number?`      | Suggested retry delay                              |

### ValidationError

Invalid parameters passed to SDK methods.

| Field       | Type                     | Description                           |
| ----------- | ------------------------ | ------------------------------------- |
| `operation` | `string`                 | Which method failed (e.g. `'search'`) |
| `fields`    | `ValidationFieldError[]` | `[{ field, code, message }]`          |

### ConfigError

SDK configuration issues at init time.

| Field      | Type      | Description                 |
| ---------- | --------- | --------------------------- |
| `field`    | `string`  | Which config field is wrong |
| `expected` | `string?` | What was expected           |

## Error helpers

The SDK provides utility functions for handling retryable errors:

```typescript theme={null}
import { isRetryable } from '@commerce-blocks/sdk'

if (result.error && isRetryable(result.error)) {
  const delay = result.error.retryAfterMs ?? 1000
  setTimeout(() => collection.execute(), delay)
}
```

## Error handling with reactive state

Handle errors reactively using the controller's `subscribe` method. This approach works with any framework:

```typescript theme={null}
const collection = client.collection({ handle: 'shirts' })

collection.subscribe(({ data, error, isFetching }) => {
  if (isFetching) {
    showLoading()
    return
  }

  if (error) {
    showError('Something went wrong. Please try again.')
    return
  }

  if (!data || data.products.length === 0) {
    showEmpty('No products found.')
    return
  }

  renderProducts(data.products)
})

await collection.execute()
```

For framework-specific patterns, see [Framework Integration](/sdk/framework-integration).
