or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdcore-configuration.mderror-handling.mdframework-integration.mdindex.mdutilities.mdvalidation.md

error-handling.mddocs/

0

# Error Handling

1

2

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.

3

4

## Capabilities

5

6

### Validation Errors

7

8

Handle configuration validation failures with detailed error information.

9

10

```python { .api }

11

class ValidationError(Exception):

12

"""Exception raised when configuration validation fails."""

13

def __init__(self, message: str, details=None): ...

14

15

@property

16

def message(self) -> str:

17

"""Primary error message."""

18

...

19

20

@property

21

def details(self) -> list:

22

"""List of detailed error information including failed validators."""

23

...

24

```

25

26

Usage examples:

27

28

```python

29

from dynaconf import Dynaconf, Validator, ValidationError

30

31

settings = Dynaconf(

32

validators=[

33

Validator("DATABASE_URL", must_exist=True),

34

Validator("PORT", cast=int, gte=1000, lte=65535),

35

Validator("DEBUG", cast=bool),

36

]

37

)

38

39

try:

40

settings.validators.validate()

41

except ValidationError as e:

42

print(f"Validation failed: {e.message}")

43

44

# Access detailed error information

45

for detail in e.details:

46

print(f" Failed validator: {detail['validator']}")

47

print(f" Key: {detail['key']}")

48

print(f" Issue: {detail['issue']}")

49

50

# Log for debugging

51

import logging

52

logging.error(f"Configuration validation error: {e}")

53

```

54

55

### Format Errors

56

57

Handle errors in configuration value formatting and lazy evaluation.

58

59

```python { .api }

60

class DynaconfFormatError(Exception):

61

"""Exception raised when formatting lazy variables fails."""

62

pass

63

```

64

65

Usage examples:

66

67

```python

68

from dynaconf import Dynaconf, DynaconfFormatError

69

70

# Configuration with invalid formatting

71

# settings.toml:

72

# message = "Hello @{UNDEFINED_VAR}!"

73

74

settings = Dynaconf(settings_files=["settings.toml"])

75

76

try:

77

formatted_message = settings.message

78

except DynaconfFormatError as e:

79

print(f"Format error in configuration: {e}")

80

81

# Provide fallback value

82

formatted_message = "Hello World!"

83

84

# Or use safe access

85

formatted_message = settings.get("message", "Default message")

86

```

87

88

### Parse Errors

89

90

Handle errors in parsing @cast directives and type conversions.

91

92

```python { .api }

93

class DynaconfParseError(Exception):

94

"""Exception raised when parsing @cast directives fails."""

95

pass

96

```

97

98

Usage examples:

99

100

```python

101

from dynaconf import Dynaconf, DynaconfParseError

102

103

# Configuration with invalid casting

104

# settings.toml:

105

# port = "@int invalid_number"

106

# config = "@json {invalid json}"

107

108

settings = Dynaconf(settings_files=["settings.toml"])

109

110

try:

111

port = settings.port

112

except DynaconfParseError as e:

113

print(f"Parse error: {e}")

114

# Use default value

115

port = 8000

116

117

try:

118

config_data = settings.config

119

except DynaconfParseError as e:

120

print(f"JSON parse error: {e}")

121

# Use empty dict as fallback

122

config_data = {}

123

```

124

125

## Error Handling Patterns

126

127

### Comprehensive Error Handling

128

129

Handle all dynaconf exceptions in a unified way.

130

131

```python

132

from dynaconf import (

133

Dynaconf, ValidationError, DynaconfFormatError,

134

DynaconfParseError, Validator

135

)

136

import logging

137

138

def create_robust_settings():

139

"""Create settings with comprehensive error handling."""

140

try:

141

settings = Dynaconf(

142

envvar_prefix="MYAPP",

143

settings_files=["config.toml", "local.yaml"],

144

environments=True,

145

validators=[

146

Validator("DATABASE_URL", must_exist=True),

147

Validator("PORT", cast=int, default=8000),

148

Validator("DEBUG", cast=bool, default=False),

149

]

150

)

151

152

# Validate configuration

153

settings.validators.validate()

154

155

return settings

156

157

except ValidationError as e:

158

logging.error(f"Configuration validation failed: {e.message}")

159

for detail in e.details:

160

logging.error(f" {detail}")

161

raise

162

163

except DynaconfFormatError as e:

164

logging.error(f"Configuration format error: {e}")

165

raise

166

167

except DynaconfParseError as e:

168

logging.error(f"Configuration parse error: {e}")

169

raise

170

171

except Exception as e:

172

logging.error(f"Unexpected configuration error: {e}")

173

raise

174

175

# Usage with error handling

176

try:

177

settings = create_robust_settings()

178

print("Configuration loaded successfully!")

179

except Exception as e:

180

print(f"Failed to load configuration: {e}")

181

# Use fallback configuration or exit gracefully

182

```

183

184

### Graceful Degradation

185

186

Implement fallback strategies when configuration loading fails.

187

188

```python

189

def get_settings_with_fallback():

190

"""Get settings with graceful degradation to defaults."""

191

default_settings = {

192

'DATABASE_URL': 'sqlite:///default.db',

193

'PORT': 8000,

194

'DEBUG': True,

195

'SECRET_KEY': 'development-only-key',

196

}

197

198

try:

199

# Try to load full configuration

200

settings = Dynaconf(

201

settings_files=["config.toml", "production.yaml"],

202

environments=True,

203

validators=[

204

Validator("DATABASE_URL", must_exist=True),

205

Validator("SECRET_KEY", must_exist=True),

206

]

207

)

208

209

settings.validators.validate()

210

return settings

211

212

except ValidationError as e:

213

print(f"Validation failed, using partial configuration: {e.message}")

214

215

# Create minimal settings with available values

216

settings = Dynaconf(environments=False)

217

218

# Apply defaults for missing required values

219

for key, default_value in default_settings.items():

220

if not settings.exists(key):

221

settings.set(key, default_value)

222

223

return settings

224

225

except (DynaconfFormatError, DynaconfParseError) as e:

226

print(f"Configuration parse error, using defaults: {e}")

227

228

# Return minimal settings with defaults

229

settings = Dynaconf(environments=False)

230

for key, value in default_settings.items():

231

settings.set(key, value)

232

233

return settings

234

235

# Safe configuration access

236

def safe_get_setting(settings, key, default=None, cast=None):

237

"""Safely get setting value with error handling."""

238

try:

239

return settings.get(key, default=default, cast=cast)

240

except (DynaconfFormatError, DynaconfParseError) as e:

241

logging.warning(f"Error accessing setting '{key}': {e}")

242

return default

243

```

244

245

### Environment-Specific Error Handling

246

247

Handle errors differently based on the environment.

248

249

```python

250

def handle_configuration_error(error, current_env="development"):

251

"""Handle configuration errors based on environment."""

252

253

if current_env == "production":

254

# In production, log error and exit

255

logging.critical(f"Production configuration error: {error}")

256

import sys

257

sys.exit(1)

258

259

elif current_env == "development":

260

# In development, warn and continue with defaults

261

logging.warning(f"Development configuration error: {error}")

262

print(f"Warning: {error}")

263

return True # Continue execution

264

265

elif current_env == "testing":

266

# In testing, use minimal configuration

267

logging.info(f"Testing configuration error (expected): {error}")

268

return True

269

270

else:

271

# Unknown environment, be conservative

272

logging.error(f"Configuration error in unknown environment: {error}")

273

raise error

274

275

def create_environment_aware_settings():

276

"""Create settings with environment-aware error handling."""

277

current_env = os.environ.get("APP_ENV", "development")

278

279

try:

280

settings = Dynaconf(

281

envvar_prefix="MYAPP",

282

settings_files=["config.toml"],

283

environments=True,

284

validators=[

285

Validator("DATABASE_URL", must_exist=True),

286

# More strict validation in production

287

Validator("SECRET_KEY", must_exist=(current_env == "production")),

288

]

289

)

290

291

settings.validators.validate()

292

return settings

293

294

except ValidationError as e:

295

if handle_configuration_error(e, current_env):

296

# Create minimal settings for non-production

297

return Dynaconf(environments=False)

298

else:

299

raise

300

```

301

302

### Custom Error Classes

303

304

Create application-specific error classes for better error handling.

305

306

```python

307

class ConfigurationError(Exception):

308

"""Base class for configuration-related errors."""

309

pass

310

311

class MissingRequiredSettingError(ConfigurationError):

312

"""Error for missing required configuration values."""

313

def __init__(self, key, environment=None):

314

self.key = key

315

self.environment = environment

316

env_msg = f" in environment '{environment}'" if environment else ""

317

super().__init__(f"Required setting '{key}' is missing{env_msg}")

318

319

class InvalidSettingValueError(ConfigurationError):

320

"""Error for invalid configuration values."""

321

def __init__(self, key, value, expected_type):

322

self.key = key

323

self.value = value

324

self.expected_type = expected_type

325

super().__init__(

326

f"Invalid value for '{key}': {value} (expected {expected_type})"

327

)

328

329

def validate_settings_strictly(settings):

330

"""Perform strict validation with custom error types."""

331

required_settings = {

332

"DATABASE_URL": str,

333

"SECRET_KEY": str,

334

"PORT": int,

335

"DEBUG": bool,

336

}

337

338

for key, expected_type in required_settings.items():

339

# Check existence

340

if not settings.exists(key):

341

raise MissingRequiredSettingError(key, settings.current_env)

342

343

# Check type

344

value = settings.get(key)

345

if not isinstance(value, expected_type):

346

raise InvalidSettingValueError(key, value, expected_type)

347

348

# Usage with custom error handling

349

try:

350

settings = Dynaconf(settings_files=["config.toml"])

351

validate_settings_strictly(settings)

352

except MissingRequiredSettingError as e:

353

print(f"Missing required setting: {e.key}")

354

# Handle missing setting

355

except InvalidSettingValueError as e:

356

print(f"Invalid setting value: {e.key} = {e.value}")

357

# Handle invalid value

358

except ConfigurationError as e:

359

print(f"Configuration error: {e}")

360

# Handle general configuration error

361

```

362

363

### Debugging Configuration Issues

364

365

Tools and patterns for debugging configuration problems.

366

367

```python

368

def debug_configuration_loading(settings):

369

"""Debug configuration loading issues."""

370

from dynaconf import inspect_settings, get_history

371

372

print("=== CONFIGURATION DEBUG REPORT ===")

373

print(f"Current environment: {settings.current_env}")

374

print(f"Loaded environments: {settings.loaded_envs}")

375

print()

376

377

# Show loading history

378

history = get_history(settings, include_internal=False)

379

print("Loading history:")

380

for entry in history[-10:]: # Last 10 entries

381

print(f" {entry['key']} = {entry['value']} (from {entry['loader']})")

382

print()

383

384

# Show validation issues

385

try:

386

settings.validators.validate()

387

print("All validations passed!")

388

except ValidationError as e:

389

print("Validation failures:")

390

for detail in e.details:

391

print(f" {detail}")

392

print()

393

394

# Show inspection report

395

inspect_settings(settings, dumper="yaml", print_report=True)

396

397

def trace_setting_value(settings, key):

398

"""Trace how a specific setting got its value."""

399

from dynaconf import get_history

400

401

print(f"=== TRACING SETTING: {key} ===")

402

403

# Current value

404

if settings.exists(key):

405

current_value = settings.get(key)

406

print(f"Current value: {current_value}")

407

else:

408

print("Setting does not exist")

409

return

410

411

# Loading history for this key

412

history = get_history(settings, key=key)

413

if history:

414

print("\nLoading history:")

415

for i, entry in enumerate(history):

416

print(f" {i+1}. {entry['value']} (from {entry['loader']})")

417

else:

418

print("No loading history found")

419

420

# Environment context

421

print(f"\nEnvironment: {settings.current_env}")

422

print(f"Available environments: {settings.loaded_envs}")

423

424

# Usage for debugging

425

def debug_settings_issue():

426

"""Debug a specific settings issue."""

427

try:

428

settings = Dynaconf(

429

settings_files=["config.toml", "local.yaml"],

430

environments=True

431

)

432

433

# Debug specific setting

434

trace_setting_value(settings, "DATABASE_URL")

435

436

# Full debug report

437

debug_configuration_loading(settings)

438

439

except Exception as e:

440

print(f"Error during debugging: {e}")

441

import traceback

442

traceback.print_exc()

443

```