# Errors

PyCharter's exception hierarchy for error handling.

## Exception Hierarchy

```
PyCharterError (base)
├── ConfigError
│   └── ConfigLoadError
├── ConfigValidationError
└── ExpressionError
```

## PyCharterError

Base exception for all PyCharter errors:

```python
from pycharter.shared.errors import PyCharterError

try:
    result = await pipeline.run()
except PyCharterError as e:
    print(f"PyCharter error: {e}")
```

## ConfigError

Raised for configuration loading/parsing failures:

```python
from pycharter.shared.errors import ConfigError

try:
    pipeline = Pipeline.from_config_dir("invalid/path/")
except ConfigError as e:
    print(f"Config error: {e}")
```

## ConfigValidationError

Raised when configuration fails schema validation:

```python
from pycharter.shared.errors import ConfigValidationError

try:
    pipeline = Pipeline.from_config_files(
        extract="extract.yaml",  # Missing required 'type' field
        load="load.yaml"
    )
except ConfigValidationError as e:
    print(f"Validation error: {e}")
```

## ConfigLoadError

Raised when a config file cannot be loaded:

```python
from pycharter.shared.errors import ConfigLoadError

try:
    pipeline = Pipeline.from_config_files(
        extract="nonexistent.yaml",
        load="load.yaml"
    )
except ConfigLoadError as e:
    print(f"Load error: {e}")
```

## ExpressionError

Raised when expression evaluation fails:

```python
from pycharter.shared.errors import ExpressionError

try:
    transform = AddField("result", "invalid_function()")
except ExpressionError as e:
    print(f"Expression error: {e}")
```

## ErrorMode

Control how pipeline errors are handled:

```python
from pycharter.shared.errors import ErrorMode, ErrorContext

# STRICT: Raise on first error (default)
result = await pipeline.run(
    error_context=ErrorContext(mode=ErrorMode.STRICT)
)

# LENIENT: Log and continue
result = await pipeline.run(
    error_context=ErrorContext(mode=ErrorMode.LENIENT)
)

# COLLECT: Gather all errors
result = await pipeline.run(
    error_context=ErrorContext(mode=ErrorMode.COLLECT)
)
print(result.errors)
```

## ErrorContext

::: pycharter.shared.errors.ErrorContext
    options:
      show_root_heading: true

## Best Practices

### Catch Specific Exceptions

```python
from pycharter.shared.errors import (
    PyCharterError,
    ConfigError,
    ConfigValidationError,
    ExpressionError
)

try:
    pipeline = Pipeline.from_config_dir("pipelines/")
    result = await pipeline.run()
except ConfigValidationError as e:
    # Handle invalid config
    print(f"Invalid configuration: {e}")
except ConfigError as e:
    # Handle missing/corrupt config
    print(f"Configuration error: {e}")
except ExpressionError as e:
    # Handle expression errors
    print(f"Expression error: {e}")
except PyCharterError as e:
    # Catch-all for other PyCharter errors
    print(f"PyCharter error: {e}")
```

### Use ErrorContext for Batch Processing

```python
# Collect errors for batch analysis
error_context = ErrorContext(mode=ErrorMode.COLLECT)
result = await pipeline.run(error_context=error_context)

if result.errors:
    # Log all errors
    for error in result.errors:
        logger.error(f"Pipeline error: {error}")
    
    # Decide whether to fail
    if len(result.errors) > 10:
        raise Exception(f"Too many errors: {len(result.errors)}")
```
