or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bytecode-caching.mdenvironment-templates.mderror-handling-debugging.mdextensions-custom-syntax.mdfilters-data-processing.mdindex.mdmeta-analysis.mdnative-types.mdsecurity-sandboxing.mdtemplate-loaders.mdtests-conditionals.md

error-handling-debugging.mddocs/

0

# Error Handling and Debugging

1

2

Comprehensive exception hierarchy and debugging tools for template development including detailed error messages, source location tracking, and runtime debugging capabilities.

3

4

## Capabilities

5

6

### Exception Hierarchy

7

8

Jinja2 provides a comprehensive exception hierarchy for different types of template errors.

9

10

```python { .api }

11

class TemplateError(Exception):

12

"""

13

Base class for all template-related errors.

14

15

Attributes:

16

message: Error message

17

lineno: Line number where error occurred (if available)

18

name: Template name where error occurred (if available)

19

filename: Template filename where error occurred (if available)

20

"""

21

22

class TemplateNotFound(TemplateError):

23

"""

24

Raised when a template cannot be found.

25

26

Attributes:

27

name: Template name that was not found

28

message: Error message

29

"""

30

31

class TemplatesNotFound(TemplateNotFound):

32

"""

33

Raised when multiple templates cannot be found (used by select_template).

34

35

Attributes:

36

names: List of template names that were not found

37

message: Error message including all attempted names

38

"""

39

40

class TemplateSyntaxError(TemplateError):

41

"""

42

Raised when template syntax is malformed.

43

44

Attributes:

45

message: Detailed syntax error message

46

lineno: Line number of syntax error

47

name: Template name

48

filename: Template filename

49

source: Template source code (if available)

50

"""

51

52

class TemplateRuntimeError(TemplateError):

53

"""

54

Raised during template execution for runtime errors.

55

56

Attributes:

57

message: Runtime error message

58

lineno: Line number where error occurred

59

name: Template name

60

filename: Template filename

61

"""

62

63

class TemplateAssertionError(TemplateRuntimeError):

64

"""

65

Raised when template assertion fails ({% assert %} tag).

66

67

Attributes:

68

message: Assertion error message

69

lineno: Line number of failed assertion

70

name: Template name

71

filename: Template filename

72

"""

73

74

class UndefinedError(TemplateRuntimeError):

75

"""

76

Raised when undefined variable is used inappropriately.

77

78

Attributes:

79

message: Undefined error message

80

name: Variable name that was undefined

81

exc_info: Original exception info (if available)

82

"""

83

84

class SecurityError(TemplateRuntimeError):

85

"""

86

Raised when template tries to perform insecure operations in sandbox mode.

87

88

Attributes:

89

message: Security violation description

90

lineno: Line number where violation occurred

91

name: Template name

92

filename: Template filename

93

"""

94

95

class FilterArgumentError(TemplateRuntimeError):

96

"""

97

Raised when filter is called with inappropriate arguments.

98

99

Attributes:

100

message: Argument error description

101

filter_name: Name of filter that failed (if available)

102

lineno: Line number where error occurred

103

name: Template name

104

filename: Template filename

105

"""

106

```

107

108

### Undefined Types for Debugging

109

110

Specialized undefined types that provide different behaviors for debugging and error handling.

111

112

```python { .api }

113

class Undefined:

114

"""

115

Default undefined type that raises UndefinedError on most operations.

116

117

Methods:

118

_undefined_hint: Get hint about undefined variable

119

_undefined_obj: Get undefined object info

120

_undefined_name: Get undefined variable name

121

_undefined_exception: Get undefined exception type

122

"""

123

124

class StrictUndefined(Undefined):

125

"""

126

Undefined that raises errors on any operation including __str__ and __iter__.

127

More strict than default Undefined for catching undefined usage early.

128

"""

129

130

class DebugUndefined(Undefined):

131

"""

132

Undefined that shows debug information when printed instead of raising errors.

133

Useful for template development and debugging.

134

135

When rendered shows: {{ undefined value 'variable_name' }}

136

"""

137

138

class ChainableUndefined(Undefined):

139

"""

140

Undefined that doesn't raise errors on getattr/getitem operations.

141

Allows chaining operations on undefined values without immediate errors.

142

143

Example: {{ undefined_obj.attr.nested_attr }} won't raise until final rendering

144

"""

145

146

def make_logging_undefined(logger=None, base=None):

147

"""

148

Create an undefined class that logs undefined variable access.

149

150

Parameters:

151

logger: Logger instance to use (default: creates new logger)

152

base: Base undefined class (default: Undefined)

153

154

Returns:

155

class: Custom undefined class that logs access attempts

156

"""

157

```

158

159

Usage examples:

160

161

```python

162

from jinja2 import Environment, DebugUndefined, StrictUndefined

163

164

# Debug mode - shows undefined variables without errors

165

debug_env = Environment(undefined=DebugUndefined)

166

template = debug_env.from_string('Hello {{ name }}! Age: {{ user.age }}')

167

result = template.render()

168

# Result: Hello {{ undefined value 'name' }}! Age: {{ undefined value 'user' }}

169

170

# Strict mode - raises errors immediately

171

strict_env = Environment(undefined=StrictUndefined)

172

template = strict_env.from_string('Hello {{ name }}!')

173

try:

174

result = template.render() # Raises UndefinedError

175

except UndefinedError as e:

176

print(f'Undefined variable: {e}')

177

178

# Logging undefined access

179

import logging

180

logging.basicConfig(level=logging.WARNING)

181

LoggingUndefined = make_logging_undefined()

182

log_env = Environment(undefined=LoggingUndefined)

183

template = log_env.from_string('Hello {{ name }}!')

184

result = template.render() # Logs warning about undefined 'name'

185

```

186

187

### Error Context and Debugging

188

189

Tools for understanding and debugging template errors with detailed context information.

190

191

```python { .api }

192

def get_template_module(env, template_name):

193

"""

194

Get template module for introspection and debugging.

195

196

Parameters:

197

env: Jinja2 environment

198

template_name: Name of template to introspect

199

200

Returns:

201

TemplateModule: Module with template exports and metadata

202

"""

203

204

def render_template_with_context(template, **context):

205

"""

206

Render template and return both result and execution context.

207

208

Parameters:

209

template: Template instance

210

**context: Template context variables

211

212

Returns:

213

tuple: (rendered_output, execution_context)

214

"""

215

```

216

217

## Error Handling Patterns

218

219

### Graceful Error Handling

220

221

Handle template errors gracefully in production applications:

222

223

```python

224

from jinja2 import Environment, TemplateNotFound, TemplateSyntaxError, TemplateRuntimeError

225

from jinja2 import FileSystemLoader, select_autoescape

226

import logging

227

228

logger = logging.getLogger(__name__)

229

230

class RobustTemplateRenderer:

231

def __init__(self):

232

self.env = Environment(

233

loader=FileSystemLoader('templates'),

234

autoescape=select_autoescape(),

235

undefined=ChainableUndefined # Don't fail on undefined variables

236

)

237

238

def render_template(self, template_name, fallback_template=None, **context):

239

"""

240

Render template with comprehensive error handling.

241

242

Parameters:

243

template_name: Primary template to render

244

fallback_template: Fallback template if primary fails

245

**context: Template context variables

246

247

Returns:

248

str: Rendered template or error message

249

"""

250

try:

251

template = self.env.get_template(template_name)

252

return template.render(**context)

253

254

except TemplateNotFound as e:

255

logger.error(f'Template not found: {e}')

256

if fallback_template:

257

try:

258

template = self.env.get_template(fallback_template)

259

return template.render(**context)

260

except Exception as fallback_error:

261

logger.error(f'Fallback template failed: {fallback_error}')

262

return f'<p>Template {template_name} not found</p>'

263

264

except TemplateSyntaxError as e:

265

logger.error(f'Template syntax error in {e.name} at line {e.lineno}: {e.message}')

266

return f'<p>Template syntax error in {template_name}</p>'

267

268

except TemplateRuntimeError as e:

269

logger.error(f'Template runtime error in {e.name} at line {e.lineno}: {e.message}')

270

return f'<p>Template runtime error in {template_name}</p>'

271

272

except Exception as e:

273

logger.error(f'Unexpected error rendering {template_name}: {e}')

274

return f'<p>Error rendering template {template_name}</p>'

275

276

# Usage

277

renderer = RobustTemplateRenderer()

278

result = renderer.render_template('user_profile.html', 'default_profile.html', user=user_data)

279

```

280

281

### Development Error Display

282

283

Detailed error display for development environments:

284

285

```python

286

from jinja2 import Environment, TemplateSyntaxError, TemplateRuntimeError

287

from jinja2 import DictLoader, DebugUndefined

288

import traceback

289

import html

290

291

class DevelopmentTemplateRenderer:

292

def __init__(self):

293

self.env = Environment(

294

loader=DictLoader({}),

295

undefined=DebugUndefined, # Show undefined variables

296

auto_reload=True # Reload templates on changes

297

)

298

299

def render_with_debug(self, template_source, **context):

300

"""

301

Render template with detailed debugging information.

302

303

Parameters:

304

template_source: Template source code

305

**context: Template context variables

306

307

Returns:

308

str: Rendered template or detailed error page

309

"""

310

try:

311

template = self.env.from_string(template_source)

312

return template.render(**context)

313

314

except TemplateSyntaxError as e:

315

return self._format_syntax_error(e, template_source)

316

317

except TemplateRuntimeError as e:

318

return self._format_runtime_error(e, template_source, context)

319

320

except Exception as e:

321

return self._format_generic_error(e, template_source, context)

322

323

def _format_syntax_error(self, error, source):

324

"""Format syntax error with source context."""

325

lines = source.split('\n')

326

error_line = error.lineno - 1 if error.lineno else 0

327

328

context_lines = []

329

for i, line in enumerate(lines):

330

line_num = i + 1

331

marker = ' >>> ' if i == error_line else ' '

332

context_lines.append(f'{marker}{line_num:3d}: {html.escape(line)}')

333

334

return f'''

335

<h2>Template Syntax Error</h2>

336

<p><strong>Error:</strong> {html.escape(str(error))}</p>

337

<p><strong>Line:</strong> {error.lineno}</p>

338

<h3>Template Source:</h3>

339

<pre>{"".join(context_lines)}</pre>

340

'''

341

342

def _format_runtime_error(self, error, source, context):

343

"""Format runtime error with context information."""

344

tb = traceback.format_exc()

345

346

return f'''

347

<h2>Template Runtime Error</h2>

348

<p><strong>Error:</strong> {html.escape(str(error))}</p>

349

<p><strong>Line:</strong> {error.lineno}</p>

350

<h3>Context Variables:</h3>

351

<pre>{html.escape(str(context))}</pre>

352

<h3>Template Source:</h3>

353

<pre>{html.escape(source)}</pre>

354

<h3>Full Traceback:</h3>

355

<pre>{html.escape(tb)}</pre>

356

'''

357

358

def _format_generic_error(self, error, source, context):

359

"""Format generic error with all available information."""

360

tb = traceback.format_exc()

361

362

return f'''

363

<h2>Template Error</h2>

364

<p><strong>Error Type:</strong> {type(error).__name__}</p>

365

<p><strong>Error:</strong> {html.escape(str(error))}</p>

366

<h3>Context Variables:</h3>

367

<pre>{html.escape(str(context))}</pre>

368

<h3>Template Source:</h3>

369

<pre>{html.escape(source)}</pre>

370

<h3>Full Traceback:</h3>

371

<pre>{html.escape(tb)}</pre>

372

'''

373

374

# Usage

375

dev_renderer = DevelopmentTemplateRenderer()

376

result = dev_renderer.render_with_debug(

377

'Hello {{ user.name }}! You have {{ user.messages | lenght }} messages.',

378

user={'name': 'Alice'}

379

)

380

```

381

382

### Template Validation

383

384

Validate templates before rendering to catch errors early:

385

386

```python

387

from jinja2 import Environment, TemplateSyntaxError

388

from jinja2.meta import find_undeclared_variables

389

import ast

390

391

class TemplateValidator:

392

def __init__(self, env):

393

self.env = env

394

395

def validate_template(self, source, required_vars=None, available_vars=None):

396

"""

397

Validate template syntax and variable usage.

398

399

Parameters:

400

source: Template source code

401

required_vars: Set of variables that must be used

402

available_vars: Set of variables that are available

403

404

Returns:

405

dict: Validation results with errors and warnings

406

"""

407

results = {

408

'valid': True,

409

'errors': [],

410

'warnings': [],

411

'undeclared_vars': set(),

412

'syntax_ok': True

413

}

414

415

# Check syntax

416

try:

417

ast_tree = self.env.parse(source)

418

results['syntax_ok'] = True

419

except TemplateSyntaxError as e:

420

results['valid'] = False

421

results['syntax_ok'] = False

422

results['errors'].append(f'Syntax error at line {e.lineno}: {e.message}')

423

return results # Can't continue without valid syntax

424

425

# Find undeclared variables

426

try:

427

undeclared = find_undeclared_variables(ast_tree)

428

results['undeclared_vars'] = undeclared

429

430

# Check against available variables

431

if available_vars is not None:

432

missing_vars = undeclared - set(available_vars)

433

if missing_vars:

434

results['warnings'].extend([

435

f'Undeclared variable: {var}' for var in missing_vars

436

])

437

438

# Check required variables are used

439

if required_vars is not None:

440

unused_required = set(required_vars) - undeclared

441

if unused_required:

442

results['warnings'].extend([

443

f'Required variable not used: {var}' for var in unused_required

444

])

445

446

except Exception as e:

447

results['errors'].append(f'Variable analysis failed: {e}')

448

449

return results

450

451

def validate_template_file(self, template_name, **validation_kwargs):

452

"""Validate template loaded from file."""

453

try:

454

template = self.env.get_template(template_name)

455

return self.validate_template(template.source, **validation_kwargs)

456

except Exception as e:

457

return {

458

'valid': False,

459

'errors': [f'Failed to load template {template_name}: {e}'],

460

'warnings': [],

461

'undeclared_vars': set(),

462

'syntax_ok': False

463

}

464

465

# Usage

466

from jinja2 import FileSystemLoader

467

468

env = Environment(loader=FileSystemLoader('templates'))

469

validator = TemplateValidator(env)

470

471

# Validate template source

472

results = validator.validate_template(

473

'Hello {{ user.name }}! You have {{ user.message_count }} messages.',

474

available_vars=['user'],

475

required_vars=['user']

476

)

477

478

if results['valid']:

479

print('Template is valid')

480

else:

481

print('Template validation failed:')

482

for error in results['errors']:

483

print(f' ERROR: {error}')

484

for warning in results['warnings']:

485

print(f' WARNING: {warning}')

486

```

487

488

## Types

489

490

```python { .api }

491

class ErrorContext:

492

"""

493

Context information for template errors.

494

495

Attributes:

496

template_name: Name of template where error occurred

497

line_number: Line number of error

498

column_number: Column number of error (if available)

499

source_line: Source code line where error occurred

500

context_vars: Template context variables at time of error

501

stack_trace: Full stack trace information

502

"""

503

504

class DebugInfo:

505

"""

506

Debug information for template execution.

507

508

Attributes:

509

template_name: Template name

510

execution_time: Template rendering time

511

context_size: Size of template context

512

undefined_vars: List of undefined variables accessed

513

filter_calls: List of filters called during rendering

514

include_chain: Chain of included/extended templates

515

"""

516

```