The dynamic configurator for your Python Project
—
Exception classes and error handling patterns for configuration parsing, validation failures, and format errors with detailed error reporting and debugging information. Understanding dynaconf's error handling helps debug configuration issues and implement robust error recovery.
Handle configuration validation failures with detailed error information.
class ValidationError(Exception):
"""Exception raised when configuration validation fails."""
def __init__(self, message: str, details=None): ...
@property
def message(self) -> str:
"""Primary error message."""
...
@property
def details(self) -> list:
"""List of detailed error information including failed validators."""
...Usage examples:
from dynaconf import Dynaconf, Validator, ValidationError
settings = Dynaconf(
validators=[
Validator("DATABASE_URL", must_exist=True),
Validator("PORT", cast=int, gte=1000, lte=65535),
Validator("DEBUG", cast=bool),
]
)
try:
settings.validators.validate()
except ValidationError as e:
print(f"Validation failed: {e.message}")
# Access detailed error information
for detail in e.details:
print(f" Failed validator: {detail['validator']}")
print(f" Key: {detail['key']}")
print(f" Issue: {detail['issue']}")
# Log for debugging
import logging
logging.error(f"Configuration validation error: {e}")Handle errors in configuration value formatting and lazy evaluation.
class DynaconfFormatError(Exception):
"""Exception raised when formatting lazy variables fails."""
passUsage examples:
from dynaconf import Dynaconf, DynaconfFormatError
# Configuration with invalid formatting
# settings.toml:
# message = "Hello @{UNDEFINED_VAR}!"
settings = Dynaconf(settings_files=["settings.toml"])
try:
formatted_message = settings.message
except DynaconfFormatError as e:
print(f"Format error in configuration: {e}")
# Provide fallback value
formatted_message = "Hello World!"
# Or use safe access
formatted_message = settings.get("message", "Default message")Handle errors in parsing @cast directives and type conversions.
class DynaconfParseError(Exception):
"""Exception raised when parsing @cast directives fails."""
passUsage examples:
from dynaconf import Dynaconf, DynaconfParseError
# Configuration with invalid casting
# settings.toml:
# port = "@int invalid_number"
# config = "@json {invalid json}"
settings = Dynaconf(settings_files=["settings.toml"])
try:
port = settings.port
except DynaconfParseError as e:
print(f"Parse error: {e}")
# Use default value
port = 8000
try:
config_data = settings.config
except DynaconfParseError as e:
print(f"JSON parse error: {e}")
# Use empty dict as fallback
config_data = {}Handle all dynaconf exceptions in a unified way.
from dynaconf import (
Dynaconf, ValidationError, DynaconfFormatError,
DynaconfParseError, Validator
)
import logging
def create_robust_settings():
"""Create settings with comprehensive error handling."""
try:
settings = Dynaconf(
envvar_prefix="MYAPP",
settings_files=["config.toml", "local.yaml"],
environments=True,
validators=[
Validator("DATABASE_URL", must_exist=True),
Validator("PORT", cast=int, default=8000),
Validator("DEBUG", cast=bool, default=False),
]
)
# Validate configuration
settings.validators.validate()
return settings
except ValidationError as e:
logging.error(f"Configuration validation failed: {e.message}")
for detail in e.details:
logging.error(f" {detail}")
raise
except DynaconfFormatError as e:
logging.error(f"Configuration format error: {e}")
raise
except DynaconfParseError as e:
logging.error(f"Configuration parse error: {e}")
raise
except Exception as e:
logging.error(f"Unexpected configuration error: {e}")
raise
# Usage with error handling
try:
settings = create_robust_settings()
print("Configuration loaded successfully!")
except Exception as e:
print(f"Failed to load configuration: {e}")
# Use fallback configuration or exit gracefullyImplement fallback strategies when configuration loading fails.
def get_settings_with_fallback():
"""Get settings with graceful degradation to defaults."""
default_settings = {
'DATABASE_URL': 'sqlite:///default.db',
'PORT': 8000,
'DEBUG': True,
'SECRET_KEY': 'development-only-key',
}
try:
# Try to load full configuration
settings = Dynaconf(
settings_files=["config.toml", "production.yaml"],
environments=True,
validators=[
Validator("DATABASE_URL", must_exist=True),
Validator("SECRET_KEY", must_exist=True),
]
)
settings.validators.validate()
return settings
except ValidationError as e:
print(f"Validation failed, using partial configuration: {e.message}")
# Create minimal settings with available values
settings = Dynaconf(environments=False)
# Apply defaults for missing required values
for key, default_value in default_settings.items():
if not settings.exists(key):
settings.set(key, default_value)
return settings
except (DynaconfFormatError, DynaconfParseError) as e:
print(f"Configuration parse error, using defaults: {e}")
# Return minimal settings with defaults
settings = Dynaconf(environments=False)
for key, value in default_settings.items():
settings.set(key, value)
return settings
# Safe configuration access
def safe_get_setting(settings, key, default=None, cast=None):
"""Safely get setting value with error handling."""
try:
return settings.get(key, default=default, cast=cast)
except (DynaconfFormatError, DynaconfParseError) as e:
logging.warning(f"Error accessing setting '{key}': {e}")
return defaultHandle errors differently based on the environment.
def handle_configuration_error(error, current_env="development"):
"""Handle configuration errors based on environment."""
if current_env == "production":
# In production, log error and exit
logging.critical(f"Production configuration error: {error}")
import sys
sys.exit(1)
elif current_env == "development":
# In development, warn and continue with defaults
logging.warning(f"Development configuration error: {error}")
print(f"Warning: {error}")
return True # Continue execution
elif current_env == "testing":
# In testing, use minimal configuration
logging.info(f"Testing configuration error (expected): {error}")
return True
else:
# Unknown environment, be conservative
logging.error(f"Configuration error in unknown environment: {error}")
raise error
def create_environment_aware_settings():
"""Create settings with environment-aware error handling."""
current_env = os.environ.get("APP_ENV", "development")
try:
settings = Dynaconf(
envvar_prefix="MYAPP",
settings_files=["config.toml"],
environments=True,
validators=[
Validator("DATABASE_URL", must_exist=True),
# More strict validation in production
Validator("SECRET_KEY", must_exist=(current_env == "production")),
]
)
settings.validators.validate()
return settings
except ValidationError as e:
if handle_configuration_error(e, current_env):
# Create minimal settings for non-production
return Dynaconf(environments=False)
else:
raiseCreate application-specific error classes for better error handling.
class ConfigurationError(Exception):
"""Base class for configuration-related errors."""
pass
class MissingRequiredSettingError(ConfigurationError):
"""Error for missing required configuration values."""
def __init__(self, key, environment=None):
self.key = key
self.environment = environment
env_msg = f" in environment '{environment}'" if environment else ""
super().__init__(f"Required setting '{key}' is missing{env_msg}")
class InvalidSettingValueError(ConfigurationError):
"""Error for invalid configuration values."""
def __init__(self, key, value, expected_type):
self.key = key
self.value = value
self.expected_type = expected_type
super().__init__(
f"Invalid value for '{key}': {value} (expected {expected_type})"
)
def validate_settings_strictly(settings):
"""Perform strict validation with custom error types."""
required_settings = {
"DATABASE_URL": str,
"SECRET_KEY": str,
"PORT": int,
"DEBUG": bool,
}
for key, expected_type in required_settings.items():
# Check existence
if not settings.exists(key):
raise MissingRequiredSettingError(key, settings.current_env)
# Check type
value = settings.get(key)
if not isinstance(value, expected_type):
raise InvalidSettingValueError(key, value, expected_type)
# Usage with custom error handling
try:
settings = Dynaconf(settings_files=["config.toml"])
validate_settings_strictly(settings)
except MissingRequiredSettingError as e:
print(f"Missing required setting: {e.key}")
# Handle missing setting
except InvalidSettingValueError as e:
print(f"Invalid setting value: {e.key} = {e.value}")
# Handle invalid value
except ConfigurationError as e:
print(f"Configuration error: {e}")
# Handle general configuration errorTools and patterns for debugging configuration problems.
def debug_configuration_loading(settings):
"""Debug configuration loading issues."""
from dynaconf import inspect_settings, get_history
print("=== CONFIGURATION DEBUG REPORT ===")
print(f"Current environment: {settings.current_env}")
print(f"Loaded environments: {settings.loaded_envs}")
print()
# Show loading history
history = get_history(settings, include_internal=False)
print("Loading history:")
for entry in history[-10:]: # Last 10 entries
print(f" {entry['key']} = {entry['value']} (from {entry['loader']})")
print()
# Show validation issues
try:
settings.validators.validate()
print("All validations passed!")
except ValidationError as e:
print("Validation failures:")
for detail in e.details:
print(f" {detail}")
print()
# Show inspection report
inspect_settings(settings, dumper="yaml", print_report=True)
def trace_setting_value(settings, key):
"""Trace how a specific setting got its value."""
from dynaconf import get_history
print(f"=== TRACING SETTING: {key} ===")
# Current value
if settings.exists(key):
current_value = settings.get(key)
print(f"Current value: {current_value}")
else:
print("Setting does not exist")
return
# Loading history for this key
history = get_history(settings, key=key)
if history:
print("\nLoading history:")
for i, entry in enumerate(history):
print(f" {i+1}. {entry['value']} (from {entry['loader']})")
else:
print("No loading history found")
# Environment context
print(f"\nEnvironment: {settings.current_env}")
print(f"Available environments: {settings.loaded_envs}")
# Usage for debugging
def debug_settings_issue():
"""Debug a specific settings issue."""
try:
settings = Dynaconf(
settings_files=["config.toml", "local.yaml"],
environments=True
)
# Debug specific setting
trace_setting_value(settings, "DATABASE_URL")
# Full debug report
debug_configuration_loading(settings)
except Exception as e:
print(f"Error during debugging: {e}")
import traceback
traceback.print_exc()Install with Tessl CLI
npx tessl i tessl/pypi-dynaconf