Custom Error Template
Relevant source files
The following files were used as context for generating this wiki page:
Hodor provides a customizable error reporting system to handle failures when communicating with upstream services. The system utilizes the minijinja templating engine to render user-facing HTML pages for errors such as 502 Bad Gateway or 500 Internal Server Error.
By default, Hodor includes a built-in dark-themed error template. Users can override this by providing a path to a custom HTML file or by injecting custom CSS to modify the existing layout. This ensures that the proxy maintains a consistent look and feel with the gated application even during service interruptions.
Sources: README.md:144-150, src/templates.rs:11-12, AGENTS.md:28-34
Architecture and Data Flow
The error template system is integrated into the proxy request flow. When a request to an upstream service fails due to a connection timeout or a network error, the proxy module catches the failure and triggers the template rendering engine.
The diagram shows how Hodor intercepts upstream failures to serve a rendered error page instead of a raw browser error.
Sources: src/proxy.rs:77-84, src/proxy.rs:133-156, src/templates.rs:114-124
Configuration
You configure the error template behavior through environment variables or the hodor.toml file.
| Configuration Key | Environment Variable | Default | Description |
|---|---|---|---|
error_template | ERROR_TEMPLATE | Built-in | File path to a custom Jinja2 HTML template. |
custom_css | CUSTOM_CSS | Empty | Verbatim CSS injected into a <style> tag. |
disable_default_css | DISABLE_DEFAULT_CSS | false | Removes built-in styles if set to true. |
title | TITLE | Password Required | Used as the <title> and heading in templates. |
Sources: src/config.rs:24-44, README.md:73-95
Template Variables
The rendering engine passes a specific context to the Jinja2 template. If you provide a custom template via ERROR_TEMPLATE, you can utilize these variables:
| Variable | Type | Description |
|---|---|---|
title | string | The value configured in the TITLE setting. |
status_code | number | The HTTP status code (e.g., 502). |
heading | string | A short summary of the error (e.g., "Upstream Unavailable"). |
message | string | A detailed description of the failure. |
custom_css | string | The CSS string provided in CUSTOM_CSS. |
disable_default_css | bool | Boolean flag to toggle base styling. |
Sources: src/templates.rs:75-87, src/error_template.html:1-5
Implementation Details
Loading and Validation
During application startup, the AppState builder loads the template source. If ERROR_TEMPLATE is defined, the system reads the file from disk; otherwise, it uses the BUILTIN_ERROR_TEMPLATE embedded in the binary. The system immediately performs a test render using validate_error_template to ensure the template syntax is valid before the server starts.
// src/templates.rs:23-29
pub(crate) fn load_error_template(template_path: Option<&str>) -> String {
match template_path {
Some(path) => std::fs::read_to_string(path)
.expect("failed to read custom error template from ERROR_TEMPLATE path"),
None => BUILTIN_ERROR_TEMPLATE.to_string(),
}
}
Sources: src/templates.rs:23-29, src/state.rs:69-76
CSS Injection
The template engine handles CSS injection through conditional blocks. The custom_css variable is marked as safe in the template to prevent auto-escaping, allowing valid CSS rules to be applied directly.
<!-- src/error_template.html:64 -->
{% if custom_css %}<style>{{ custom_css | safe }}</style>{% endif %}
Sources: src/error_template.html:64, src/templates.rs:82
Error Handlers
Specific helper functions in src/templates.rs standardize the error responses sent by the proxy:
bad_gateway(state): Returns a 502 status with the message "Hodor is running, but the upstream service could not be reached."internal_server_error(state): Returns a 500 status when internal processing fails.
Sources: src/templates.rs:126-141, src/proxy.rs:149-155
Security and Sanitization
- XSS Protection: The
titlevariable is auto-escaped by minijinja by default to prevent Cross-Site Scripting (XSS). - Raw CSS: The
custom_cssis emitted unescaped. You must ensure the provided CSS is trusted, as it is injected directly into the HTML<style>block. - Fail-Safe Rendering: If the template engine fails to render the HTML (e.g., due to a broken custom template), the system catches the error, logs it via
tracing::warn, and falls back to a plain text error response to ensure the client receives a status code.
Sources: src/templates.rs:106-112, src/tests/templates.rs:67-73, AGENTS.md:58-62