Exception Handling Reference¶
Document Type: Reference (Diátaxis) Audience: Developers working with amplihack internals Last Updated: 2026-02-19
Overview¶
Amplihack uses a structured exception hierarchy for error handling across the CLI, hooks, and core components. All exceptions inherit from AmplihackError, enabling both broad and specific exception handling.
Exception Hierarchy¶
AmplihackError (base)
├── CLIError
│ ├── ClaudeBinaryNotFoundError
│ ├── LaunchError
│ └── AppendInstructionError
├── LauncherError
│ ├── AutoModeError
│ └── SessionNotFoundError
├── ConfigurationError
├── PluginError
└── RecipeError
├── RecipeNotFoundError
└── RecipeValidationError
Exception Classes¶
Base Exception¶
AmplihackError¶
Base exception for all amplihack-specific errors.
Usage: Catch this to handle any amplihack error broadly.
try:
# amplihack operation
pass
except AmplihackError as e:
# Handle any amplihack error
logger.error(f"Amplihack error: {e}")
CLI Exceptions¶
CLIError¶
Base exception for CLI-level errors.
ClaudeBinaryNotFoundError¶
Raised when the Claude CLI binary cannot be located or installed.
Common Causes:
- Claude CLI not installed
- Binary not in PATH
- Installation failed
Example:
from amplihack.exceptions import ClaudeBinaryNotFoundError
try:
path = require_claude_cli()
except ClaudeBinaryNotFoundError as e:
print(f"Please install Claude CLI: {e}")
LaunchError¶
Raised when launching Claude CLI fails.
Common Causes:
- Invalid arguments
- Permission issues
- Process spawn failure
AppendInstructionError¶
Raised when appending an instruction to an active session fails.
Common Causes:
- Session not found
- Communication error with Claude CLI
- Invalid instruction format
Launcher Exceptions¶
LauncherError¶
Base exception for launcher-level errors.
AutoModeError¶
Raised when auto-mode encounters a fatal error.
Common Causes:
- Invalid auto-mode configuration
- File system access issues
- Markdown rendering failure
SessionNotFoundError¶
Raised when a required active session cannot be found.
Common Causes:
- No active Claude Code sessions
- Session terminated unexpectedly
- Session search failure
Configuration Exceptions¶
ConfigurationError¶
Raised when configuration is missing or invalid.
Common Causes:
- Missing required configuration files
- Invalid JSON/YAML syntax
- Missing required fields
- Invalid configuration values
Example:
from amplihack.exceptions import ConfigurationError
try:
config = load_config()
except ConfigurationError as e:
logger.error(f"Configuration error: {e}")
# Use default configuration or exit
PluginError¶
Raised when a plugin operation fails.
Common Causes:
- Plugin not found
- Plugin initialization failure
- Git clone failure (for git-based plugins)
- Dependency conflicts
Recipe Exceptions¶
RecipeError¶
Base exception for recipe-related failures.
RecipeNotFoundError¶
Raised when a requested recipe cannot be found.
Common Causes:
- Recipe name typo
- Recipe file missing
- Invalid recipe directory structure
Example:
from amplihack.exceptions import RecipeNotFoundError
try:
recipe = load_recipe("my-recipe")
except RecipeNotFoundError as e:
print(f"Recipe not found: {e}")
# List available recipes
RecipeValidationError¶
Raised when a recipe file fails validation.
Common Causes:
- Invalid YAML syntax
- Missing required fields
- Invalid step definitions
- Circular dependencies
Exception Handling Best Practices¶
1. Always Log Exceptions¶
All exceptions should be logged at an appropriate level:
import logging
try:
risky_operation()
except AmplihackError as e:
logging.error(f"Operation failed: {e}", exc_info=True)
2. Use Specific Exception Types¶
Catch specific exceptions when you can handle them differently:
from amplihack.exceptions import (
ClaudeBinaryNotFoundError,
LaunchError,
ConfigurationError
)
try:
launch_claude()
except ClaudeBinaryNotFoundError:
# Specific handling for missing binary
install_claude_cli()
except LaunchError:
# Specific handling for launch failure
retry_launch()
except ConfigurationError:
# Specific handling for config issues
use_default_config()
3. Fail-Open for Non-Critical Operations¶
Hooks and monitoring code should fail-open (continue operation on error):
try:
collect_metrics()
except Exception as e:
# Log but don't raise - fail-open
logging.debug(f"Metrics collection failed: {e}")
4. Fail-Safe for Critical Operations¶
Critical operations should fail-safe (halt on error):
from amplihack.exceptions import ConfigurationError
try:
config = load_critical_config()
except ConfigurationError as e:
logging.error(f"Critical config failed: {e}")
sys.exit(1) # Fail-safe - cannot continue
5. Never Use Bare except¶
Always specify the exception type or use Exception:
# Bad
try:
operation()
except: # Catches everything including KeyboardInterrupt
pass
# Good
try:
operation()
except Exception as e: # Catches runtime errors only
logging.error(f"Operation failed: {e}")
Hook Exception Handling¶
Hooks implement specific exception handling patterns based on their purpose:
Session Hooks (fail-open)¶
try:
inject_context()
except Exception as e:
# Log to stderr, continue session
print(f"Warning: Context injection failed: {e}", file=sys.stderr)
Power Steering Hook (sanitized logging)¶
try:
validate_response()
except Exception as e:
# Sanitize paths/tokens before logging
_log_sdk_error("validation", e)
Stop Hook (fail-safe for lock checks)¶
try:
check_lock_flag()
except Exception as e:
# Log but allow stop - fail-safe
self.log(f"Lock check failed: {e}", level="DEBUG")
Logging Levels¶
Use appropriate logging levels based on exception severity:
| Level | Use Case | Example |
|---|---|---|
DEBUG | Expected failures, fail-open scenarios | Metrics collection failed |
WARNING | Degraded operation, using fallbacks | Config file missing, using defaults |
ERROR | Operation failed but service continues | Request failed, will retry |
CRITICAL | Fatal errors requiring immediate action | Database corruption detected |
Migration Notes¶
Pre-PR #2407 & #2409¶
Previously, many exception blocks were silent:
Post-PR #2407 & #2409¶
All exception blocks now log errors while preserving fail-open/fail-safe semantics: