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

# Error Codes

> Understanding and handling Reducto API errors

When something goes wrong, Reducto returns an HTTP status code and error message.

## Error Response Format

```json theme={null}
{
  "error": {
    "message": "Failed to download file from url. Please check the document url and try again",
    "type": "file_download_failure",
    "code": 400
  }
}
```

## Client Errors (4xx)

These errors indicate a problem with your request.

| Code | Name                    | Description                      | Solution                                                     |
| ---- | ----------------------- | -------------------------------- | ------------------------------------------------------------ |
| 400  | JSON decoding error     | LLM response too large to decode | Enable `array_extract: true` for large extraction schemas    |
| 400  | Invalid URL format      | S3 URL malformed                 | Use format `s3://bucket-name/key`                            |
| 400  | File download failure   | Cannot fetch document from URL   | Verify URL is accessible and not expired                     |
| 400  | Invalid page range      | Specified pages don't exist      | Page range is 1-indexed. Check document has requested pages  |
| 403  | Permission error        | URL access forbidden             | Ensure presigned URL hasn't expired or credentials are valid |
| 403  | PDF processing error    | Cannot write output              | Internal error, contact support                              |
| 404  | File access error       | File not found                   | Verify file exists at the specified path/URL                 |
| 415  | File conversion error   | Cannot convert to images         | Check file is a valid, uncorrupted PDF                       |
| 415  | PDF handling error      | Cannot process PDF               | File may be corrupted. Try re-saving with Adobe Acrobat      |
| 422  | Schema validation error | Invalid JSON schema              | Validate your schema is proper JSON Schema format            |
| 422  | Table processing error  | Table extraction failed          | Retry, or enable agentic table mode for complex tables       |
| 442  | Document access error   | Password protected               | Provide password via `settings.document_password`            |
| 429  | Rate limit exceeded     | Too many requests                | Implement backoff, or switch to async endpoints              |

## Server Errors (5xx)

These indicate a problem on Reducto's side. Most are automatically retried by the SDK.

| Code | Name                        | Description                | Retriable? |
| ---- | --------------------------- | -------------------------- | ---------- |
| 500  | Content extraction error    | Extraction failed          | ❌ No       |
| 500  | Citation extraction error   | Citation extraction failed | ❌ No       |
| 500  | PDF metadata error          | PDF metadata corrupted     | ❌ No       |
| 502  | LLM service error           | LLM provider error         | ✅ Yes      |
| 503  | Service unavailable         | Temporary overload         | ✅ Yes      |
| 503  | Table processing error      | Table service error        | ✅ Yes      |
| 504  | LLM timeout error           | LLM provider timed out     | ✅ Yes      |
| 504  | Document conversion timeout | Conversion took too long   | ✅ Yes      |

## Automatic Retries

The Reducto SDKs automatically retry requests that fail with these status codes:

```
408, 409, 429, and all 5xx errors (500+)
```

Default retry behavior:

* **Max retries**: 2
* **Backoff**: Exponential with jitter
* **Timeout**: 1 hour per request (3600 seconds)

You can customize retry behavior:

<CodeGroup>
  ```python Python theme={null}
  from reducto import Reducto

  client = Reducto(
      max_retries=5,
      timeout=120.0  # seconds
  )
  ```

  ```javascript Node.js theme={null}
  import Reducto from 'reductoai';

  const client = new Reducto({
    maxRetries: 5,
    timeout: 120000  // milliseconds
  });
  ```
</CodeGroup>

## Handling Errors

<CodeGroup>
  ```python Python theme={null}
  from reducto import (
      Reducto,
      APIError,
      BadRequestError,
      RateLimitError,
      APIConnectionError
  )

  client = Reducto()

  try:
      result = client.parse.run(input=upload.file_id)
  except BadRequestError as e:
      # 400-level errors (your request has a problem)
      print(f"Bad request: {e.message}")
  except RateLimitError as e:
      # 429 - too many requests
      print("Rate limited, waiting...")
      time.sleep(60)
  except APIConnectionError as e:
      # Network issues
      print(f"Connection failed: {e}")
  except APIError as e:
      # Other API errors
      print(f"API error {e.status_code}: {e.message}")
  ```

  ```javascript Node.js theme={null}
  import Reducto from 'reductoai';

  const client = new Reducto();

  try {
    const result = await client.parse.run({ input: upload.file_id });
  } catch (error) {
    if (error.status === 400) {
      console.log('Bad request:', error.message);
    } else if (error.status === 429) {
      console.log('Rate limited, waiting...');
      await new Promise(r => setTimeout(r, 60000));
    } else if (error.status >= 500) {
      console.log('Server error, will retry automatically');
    }
  }
  ```

  ```bash cURL theme={null}
  # Check response status code
  RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "https://platform.reducto.ai/parse" \
    -H "Authorization: Bearer $REDUCTO_API_KEY" \
    -d '{"input": "https://example.com/document.pdf"}')

  STATUS=$(echo "$RESPONSE" | tail -n 1)
  BODY=$(echo "$RESPONSE" | sed '$d')

  if [ "$STATUS" -eq 200 ]; then
    echo "Success: $BODY"
  elif [ "$STATUS" -eq 429 ]; then
    echo "Rate limited, waiting..."
    sleep 60
  else
    echo "Error $STATUS: $BODY"
  fi
  ```
</CodeGroup>

## Common Issues

<AccordionGroup>
  <Accordion title="400: Invalid URL format">
    **Cause**: The URL you provided isn't in a recognized format.

    **Solutions**:

    * For S3: Use `s3://bucket-name/key` format
    * For presigned URLs: Ensure the full URL including query parameters is provided
    * For reducto:// URLs: Use the exact string returned from `/upload`
  </Accordion>

  <Accordion title="403: Permission error">
    **Cause**: Reducto cannot access the file at the URL you provided.

    **Solutions**:

    * Check that presigned URLs haven't expired
    * Verify the URL is publicly accessible or properly authenticated
    * For S3, ensure the bucket policy allows access from Reducto's IPs
  </Accordion>

  <Accordion title="429: Rate limit exceeded">
    **Cause**: You've exceeded the request rate limit.

    **Solutions**:

    * Implement exponential backoff
    * Switch to async endpoints (`/parse_async`) which have higher limits
    * Use separate API keys for different applications
    * Contact support for higher limits
  </Accordion>

  <Accordion title="504: Timeout errors">
    **Cause**: The document took too long to process.

    **Solutions**:

    * Use async endpoints for large documents
    * Process fewer pages using `page_range`
    * Disable agentic modes if not needed
    * Check if the document is unusually complex
  </Accordion>
</AccordionGroup>

***

## Related

<CardGroup cols={2}>
  <Card title="Rate Limits" icon="gauge" href="/reference/rate-limits">
    Understanding request limits.
  </Card>

  <Card title="Async Processing" icon="clock" href="/workflows/async-overview">
    Avoid timeouts with async endpoints.
  </Card>
</CardGroup>
