97e91a83f3
Ruff / Ruff (push) Has been cancelled
Test / Core Tests (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.10) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.11) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.12) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.13) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.9) (push) Has been cancelled
Test / Full Coverage (Python 3.11) (push) Has been cancelled
Test / Core Provider Tests (OpenAI) (push) Has been cancelled
Test / Core Provider Tests (Anthropic) (push) Has been cancelled
Test / Core Provider Tests (Google) (push) Has been cancelled
Test / Core Provider Tests (Other) (push) Has been cancelled
Test / Anthropic Tests (push) Has been cancelled
Test / Gemini Tests (push) Has been cancelled
Test / Google GenAI Tests (push) Has been cancelled
Test / Vertex AI Tests (push) Has been cancelled
Test / OpenAI Tests (push) Has been cancelled
Test / Writer Tests (push) Has been cancelled
Test / Auto Client Tests (push) Has been cancelled
ty / type-check (push) Has been cancelled
310 lines
7.7 KiB
Markdown
310 lines
7.7 KiB
Markdown
---
|
|
title: Error Handling
|
|
description: Learn how to handle errors and exceptions when using Instructor for structured outputs.
|
|
---
|
|
|
|
# Error Handling
|
|
|
|
Instructor provides a comprehensive exception hierarchy to help you handle errors gracefully. All Instructor exceptions inherit from `InstructorError`.
|
|
|
|
## Exception Reference
|
|
|
|
| Exception | Description | Key Attributes |
|
|
|-----------|-------------|----------------|
|
|
| `InstructorError` | Base exception for all Instructor errors | - |
|
|
| `IncompleteOutputException` | Output truncated due to token limit | `last_completion` |
|
|
| `InstructorRetryException` | All retry attempts exhausted | `n_attempts`, `failed_attempts`, `total_usage` |
|
|
| `ValidationError` | Response validation failed | - |
|
|
| `ResponseParsingError` | Cannot parse LLM response | `mode`, `raw_response` |
|
|
| `ProviderError` | Provider-specific error | `provider` |
|
|
| `ConfigurationError` | Invalid configuration | - |
|
|
| `ModeError` | Invalid mode for provider | `mode`, `provider`, `valid_modes` |
|
|
| `ClientError` | Client initialization failed | - |
|
|
| `MultimodalError` | Processing image/audio/PDF failed | `content_type`, `file_path` |
|
|
| `AsyncValidationError` | Async validation failed | `errors` |
|
|
|
|
## Common Exceptions
|
|
|
|
### Incomplete Output
|
|
|
|
Raised when the LLM output is truncated due to reaching the token limit:
|
|
|
|
```python
|
|
import instructor
|
|
from pydantic import BaseModel
|
|
from instructor.core.exceptions import IncompleteOutputException, InstructorRetryException
|
|
|
|
|
|
class Report(BaseModel):
|
|
content: str
|
|
|
|
|
|
client = instructor.from_provider("openai/gpt-4.1-mini", mode=instructor.Mode.JSON)
|
|
|
|
try:
|
|
response = client.create(
|
|
response_model=Report,
|
|
messages=[{"role": "user", "content": "Write a long report..."}],
|
|
max_tokens=50,
|
|
max_retries=0,
|
|
)
|
|
except (IncompleteOutputException, InstructorRetryException) as e:
|
|
print(f"Output truncated: {e}")
|
|
print(f"Last completion: {e.last_completion}")
|
|
```
|
|
|
|
### Retry Exhausted
|
|
|
|
Raised when all retry attempts fail:
|
|
|
|
```python
|
|
import instructor
|
|
from pydantic import BaseModel
|
|
from instructor.core.exceptions import InstructorRetryException
|
|
|
|
|
|
class User(BaseModel):
|
|
name: str
|
|
age: int
|
|
|
|
|
|
client = instructor.from_provider("openai/gpt-4.1-mini")
|
|
|
|
try:
|
|
response = client.create(
|
|
response_model=User,
|
|
messages=[{"role": "user", "content": "Extract user info..."}],
|
|
max_retries=3,
|
|
)
|
|
except InstructorRetryException as e:
|
|
print(f"Failed after {e.n_attempts} attempts")
|
|
for attempt in e.failed_attempts:
|
|
print(f" Attempt {attempt.attempt_number}: {attempt.exception}")
|
|
```
|
|
|
|
### Validation Error
|
|
|
|
Raised when the response fails validation:
|
|
|
|
```python
|
|
import instructor
|
|
from pydantic import BaseModel, field_validator
|
|
from instructor.core.exceptions import ValidationError
|
|
|
|
|
|
class StrictModel(BaseModel):
|
|
value: int
|
|
|
|
@field_validator("value")
|
|
@classmethod
|
|
def validate_value(cls, v: int) -> int:
|
|
if v < 0:
|
|
raise ValueError("Value must be positive")
|
|
return v
|
|
|
|
|
|
client = instructor.from_provider("openai/gpt-4.1-mini")
|
|
|
|
try:
|
|
response = client.create(
|
|
response_model=StrictModel,
|
|
messages=[{"role": "user", "content": "Extract data..."}],
|
|
)
|
|
except ValidationError as e:
|
|
print(f"Validation failed: {e}")
|
|
```
|
|
|
|
### Provider and Configuration Errors
|
|
|
|
Raised for provider-specific issues or invalid configuration:
|
|
|
|
```python
|
|
import instructor
|
|
from instructor.core.exceptions import ConfigurationError, ModeError
|
|
|
|
# Invalid provider format
|
|
try:
|
|
client = instructor.from_provider("invalid-format")
|
|
except ConfigurationError as e:
|
|
print(f"Configuration error: {e}")
|
|
|
|
# Wrong mode for provider
|
|
try:
|
|
client = instructor.from_provider(
|
|
"openai/gpt-4.1-mini",
|
|
mode=instructor.Mode.TOOLS,
|
|
)
|
|
except ModeError as e:
|
|
print(f"Invalid mode. Valid modes: {e.valid_modes}")
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### Catch Specific Exceptions
|
|
|
|
```python
|
|
import logging
|
|
import instructor
|
|
from pydantic import BaseModel
|
|
from instructor.core.exceptions import (
|
|
IncompleteOutputException,
|
|
InstructorRetryException,
|
|
ValidationError,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class User(BaseModel):
|
|
name: str
|
|
age: int
|
|
|
|
|
|
client = instructor.from_provider("openai/gpt-4.1-mini")
|
|
|
|
try:
|
|
response = client.create(
|
|
response_model=User,
|
|
messages=[{"role": "user", "content": "Extract: Sam is 34"}],
|
|
)
|
|
except IncompleteOutputException:
|
|
logger.warning("Output truncated, retrying with more tokens")
|
|
response = client.create(
|
|
response_model=User,
|
|
messages=[{"role": "user", "content": "Extract: Sam is 34"}],
|
|
max_tokens=2000,
|
|
)
|
|
except InstructorRetryException as e:
|
|
logger.error(f"Failed after {e.n_attempts} attempts")
|
|
response = None
|
|
except ValidationError as e:
|
|
logger.error(f"Validation failed: {e}")
|
|
raise
|
|
```
|
|
|
|
### Use Base Exception for General Handling
|
|
|
|
```python
|
|
import instructor
|
|
from pydantic import BaseModel
|
|
from instructor.core.exceptions import InstructorError
|
|
|
|
|
|
class Data(BaseModel):
|
|
value: str
|
|
|
|
|
|
client = instructor.from_provider("openai/gpt-4.1-mini")
|
|
|
|
try:
|
|
response = client.create(
|
|
response_model=Data,
|
|
messages=[{"role": "user", "content": "Extract data"}],
|
|
)
|
|
except InstructorError as e:
|
|
# Catches any Instructor-specific error
|
|
print(f"Instructor error: {type(e).__name__}: {e}")
|
|
```
|
|
|
|
### Graceful Degradation
|
|
|
|
```python
|
|
import instructor
|
|
from pydantic import BaseModel, field_validator
|
|
from instructor.core.exceptions import ValidationError, InstructorRetryException
|
|
|
|
|
|
class StrictData(BaseModel):
|
|
value: int
|
|
|
|
@field_validator("value")
|
|
@classmethod
|
|
def validate_value(cls, v: int) -> int:
|
|
if v < 0:
|
|
raise ValueError("Value must be positive")
|
|
return v
|
|
|
|
|
|
class RelaxedData(BaseModel):
|
|
value: str
|
|
|
|
|
|
client = instructor.from_provider("openai/gpt-4.1-mini")
|
|
|
|
|
|
def extract_with_fallback(content: str):
|
|
try:
|
|
return client.create(
|
|
response_model=StrictData,
|
|
messages=[{"role": "user", "content": content}],
|
|
)
|
|
except ValidationError:
|
|
# Fall back to less strict model
|
|
return client.create(
|
|
response_model=RelaxedData,
|
|
messages=[{"role": "user", "content": content}],
|
|
)
|
|
except InstructorRetryException:
|
|
return None
|
|
```
|
|
|
|
## Backwards Compatibility
|
|
|
|
New exceptions inherit from both `ValueError` and `InstructorError`, so existing code continues to work:
|
|
|
|
```python
|
|
import instructor
|
|
from pydantic import BaseModel
|
|
from instructor.core.exceptions import ResponseParsingError
|
|
|
|
|
|
class User(BaseModel):
|
|
name: str
|
|
age: int
|
|
|
|
|
|
client = instructor.from_provider("openai/gpt-4.1-mini")
|
|
|
|
# Old code still works
|
|
try:
|
|
response = client.create(
|
|
response_model=User,
|
|
messages=[{"role": "user", "content": "Extract: Kai is 41"}],
|
|
)
|
|
except ValueError as e:
|
|
print(f"Error: {e}")
|
|
|
|
# New code can access additional context
|
|
try:
|
|
response = client.create(
|
|
response_model=User,
|
|
messages=[{"role": "user", "content": "Extract: Kai is 41"}],
|
|
)
|
|
except ResponseParsingError as e:
|
|
print(f"Mode: {e.mode}, Raw: {e.raw_response}")
|
|
```
|
|
|
|
## Integration with Hooks
|
|
|
|
Monitor errors using the hooks system:
|
|
|
|
```python
|
|
import instructor
|
|
from instructor.core.exceptions import ValidationError
|
|
|
|
|
|
def on_parse_error(error: Exception):
|
|
if isinstance(error, ValidationError):
|
|
print(f"Validation error: {error}")
|
|
|
|
|
|
client = instructor.from_provider("openai/gpt-4.1-mini")
|
|
client.hooks.on("parse:error", on_parse_error)
|
|
```
|
|
|
|
## See Also
|
|
|
|
- [Retrying](./retrying.md) - Retry strategies with Tenacity
|
|
- [Validation](./validation.md) - Validation patterns
|
|
- [Hooks](./hooks.md) - Error monitoring with hooks
|