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

# Error Handling

When the Extend API returns an error, the response includes an error object with a `code`, `message`, and `retryable` field to help you understand what went wrong and how to handle it. A `requestId` is also included when available. For validation errors, a `docUrl` field may also be present with a link to relevant documentation.

## Error Response Structure

```json
{
  "code": "INVALID_REQUEST",
  "message": "Non-nullable primitive type \"string\" is not allowed. Use [\"string\", \"null\"] instead of \"string\".; Path: schema.properties.name",
  "retryable": false,
  "requestId": "req_Xj8mK2pL9nR4vT7qY5wZ",
  "docUrl": "https://docs.extend.ai/2026-02-09/extraction/schema#primitive-schema"
}
```

| Field       | Type              | Description                                                 |
| ----------- | ----------------- | ----------------------------------------------------------- |
| `code`      | string            | Error code for programmatic handling                        |
| `message`   | string            | Human-readable error description                            |
| `retryable` | boolean           | Whether the request can be retried with exponential backoff |
| `requestId` | string            | Unique identifier for support purposes                      |
| `docUrl`    | string (optional) | Link to relevant documentation for resolving the error      |

## General Error Codes

These error codes are returned across all endpoints:

| Error Code            | Description                                                                                   | Retryable |
| --------------------- | --------------------------------------------------------------------------------------------- | --------- |
| `INVALID_REQUEST`     | The request body or parameters are invalid (e.g. missing required fields, validation errors). | ❌         |
| `UNAUTHORIZED`        | Authentication failed — the API key is missing, malformed, or invalid.                        | ❌         |
| `NOT_FOUND`           | The requested resource does not exist.                                                        | ❌         |
| `RATE_LIMIT_EXCEEDED` | Too many requests. Back off and retry.                                                        | ✅         |
| `USAGE_BLOCKED`       | Organization usage is blocked due to insufficient credits.                                    | ❌         |
| `ENDPOINT_REMOVED`    | The endpoint has been deprecated and removed. The `message` will indicate the replacement.    | ❌         |
| `INTERNAL_ERROR`      | An unexpected server error occurred.                                                          | ✅         |

Domain-specific error codes (e.g. for [parse runs](/2026-02-09/parsing/error-handling), extract runs) are also returned — use the `retryable` field to determine if a request can be retried, and the `message` field for debugging.

## Handling Errors

### Recommended Approach

1. **Check `retryable`** to determine if the request can be retried
2. **Use the `code`** for specific programmatic handling
3. **Log the `requestId`** for debugging and support requests
4. **Display the `message`** to users when appropriate
5. **Check `docUrl`** for a link to documentation that can help resolve the error

### Example Error Handling

```python Python
from extend_ai import Extend
from extend_ai.core import ApiError

client = Extend(token="your_api_key")

try:
    result = client.extract(
        extractor={"id": "your_extractor_id"},
        file={"url": "https://example.com/document.pdf"},
    )
except ApiError as error:
    # error.body contains the parsed JSON response
    body = error.body or {}

    if body.get("retryable"):
        # Retry with exponential backoff
        return retry()

    # Log error details for debugging
    print(f"API error: {body.get('code')}, message: {body.get('message')}, requestId: {body.get('requestId')}")

    # If a documentation link is provided, log it for easy reference
    if body.get("docUrl"):
        print(f"See documentation: {body.get('docUrl')}")

    raise
```

```typescript TypeScript
import { ExtendClient, ExtendError } from "extend-ai";

const client = new ExtendClient({ token: "your_api_key" });

try {
  const result = await client.extract({
    extractor: { id: "your_extractor_id" },
    file: { url: "https://example.com/document.pdf" },
  });
} catch (error) {
  if (error instanceof ExtendError) {
    // error.body contains the parsed JSON response
    const body = error.body as {
      code: string;
      message: string;
      retryable: boolean;
      requestId: string;
      docUrl?: string;
    };

    if (body.retryable) {
      // Retry with exponential backoff
      await sleep(1000);
      return retry();
    }

    // Log error details for debugging
    console.error(`API error: ${body.code}, message: ${body.message}, requestId: ${body.requestId}`);

    // If a documentation link is provided, log it for easy reference
    if (body.docUrl) {
      console.error(`See documentation: ${body.docUrl}`);
    }
  }
  throw error;
}
```

```java Java
import ai.extend.ExtendClient;
import ai.extend.core.ExtendClientApiException;
import ai.extend.requests.ExtractRequest;
import ai.extend.types.ExtractRequestExtractor;
import ai.extend.types.ExtractRequestFile;
import ai.extend.types.FileFromUrl;
import java.util.Map;

ExtendClient client = ExtendClient.builder().apiKey("your_api_key").build();

try {
    client.extract(ExtractRequest.builder()
        .file(ExtractRequestFile.of(FileFromUrl.builder()
            .url("https://example.com/document.pdf")
            .build()))
        .extractor(ExtractRequestExtractor.builder().id("your_extractor_id").build())
        .build());
} catch (ExtendClientApiException e) {
    // e.body() is the parsed JSON response; e.statusCode() is the HTTP status
    @SuppressWarnings("unchecked")
    Map<String, Object> body = (Map<String, Object>) e.body();

    if (Boolean.TRUE.equals(body.get("retryable"))) {
        // Retry with exponential backoff
    }

    // Log error details for debugging
    System.err.printf("API error: %s, message: %s, requestId: %s%n",
        body.get("code"), body.get("message"), body.get("requestId"));

    // If a documentation link is provided, log it for easy reference
    if (body.get("docUrl") != null) {
        System.err.println("See documentation: " + body.get("docUrl"));
    }
    throw e;
}
```

```go Go
import (
	"context"
	"errors"
	"fmt"

	extend "github.com/extend-hq/extend-go-sdk"
	client "github.com/extend-hq/extend-go-sdk/client"
	core "github.com/extend-hq/extend-go-sdk/core"
	option "github.com/extend-hq/extend-go-sdk/option"
)

c := client.NewClient(option.WithToken("your_api_key"))

_, err := c.Extract(context.TODO(), &extend.ExtractRequest{
	Extractor: &extend.ExtractRequestExtractor{ID: "your_extractor_id"},
	File:      &extend.ExtractRequestFile{FileFromURL: &extend.FileFromURL{URL: "https://example.com/document.pdf"}},
})
if err != nil {
	// Inspect the structured API error for the status code
	var apiErr *core.APIError
	if errors.As(err, &apiErr) {
		fmt.Printf("API error (status %d): %s\n", apiErr.StatusCode, apiErr.Error())
	}
	// Typed variants (e.g. *extend.BadRequestError) expose the raw JSON body via .Body
	return err
}
```

## Getting Help

When contacting support about an error, always include:

1. The `requestId` from the error response
2. The timestamp of when the error occurred
3. The endpoint you were calling
4. The error `code`

This information helps us quickly identify and resolve issues.