Skip to content

Error Handling ​

Errors Throw by Default ​

render() rejects with a CompileError when the template is malformed and with a RenderError when it fails while running. Both carry a details property with the offending source line highlighted:

typescript
import { render, CompileError } from 'janja';

try {
  await render('{{ for }}', {});
} catch (error) {
  if (error instanceof CompileError) {
    console.log(error.details);
    // "for" requires expression
    //
    // 1│ {{ for }}
    //  │ ^       ^
  }
}

Lenient Mode ​

To keep rendering instead, pass a debug handler. Every error is handed to it, malformed directives are skipped, unclosed blocks are closed at the end of the template, and a template that fails while running renders as an empty string:

typescript
const html = await render(template, data, {
  debug: (error) => logger.warn(error.details ?? error.message),
});

Missing Values ​

null and undefined render as an empty string, and looping over them runs the else branch of the loop. Reading a property of a missing value ({{= user.name }} without user) is an error.

Template Validation ​

validateTemplate() runs a template through the real parser without rendering it, and reports every syntax error with its position, plus warnings for filters that are not registered:

typescript
import { validateTemplate } from 'janja';

const result = await validateTemplate('Hello {{= name | uper }}{{ endif }}');

result.valid; // false
result.errors; // [{ type: 'error', message: 'Unexpected "endif"', line: 1, column: 25, suggestion: '...' }]
result.warnings; // [{ type: 'warning', message: 'Unknown filter "uper"', line: 1, column: 15 }]

Pass the same options as the renderer (custom delimiters, filters, plugins) as the second argument.

Common Error Messages ​

  • "if" requires expression: a directive that needs an expression has none
  • Unclosed "if": a block directive is missing its endif / endfor / endblock / ...
  • Unexpected "endif": a closing or branch directive has no matching opening directive
  • Unknown "name": {{ name }} is not a directive; use {{= name }} to output a value
  • "constructor" is not allowed in expressions: see Security

Released under the MIT License.