> ## 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 |
| 413 | Image too large | Image exceeds maximum dimensions | Resize image to under 50 megapixels total and 15,000 pixels per axis. See [image limits](/upload/overview#supported-file-types) |
| 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="413: Image too large">
    **Cause**: An image in your document exceeds the maximum supported dimensions (50 megapixels total or 15,000 pixels on any single axis).

    **Solutions**:

    * Resize or re-export images to stay under 50 megapixels (e.g., under \~8200x6100)
    * Ensure no single axis exceeds 15,000 pixels
    * For scanned documents, reduce the scan DPI
  </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>
