stalwartlabs/stalwart · error
Failed to parse calendar template
Error message
Failed to parse calendar template
What it means
This panic occurs during GroupwareConfig construction when the embedded, minified calendar-alarm HTML template fails Template::parse. Because include_str! bakes resources/html-templates/calendar-alarm.html.min into the binary at compile time, the .expect() should never fire in normal operation; if it does, the shipped template content is corrupt or incompatible with the current Template parser.
Source
Thrown at crates/common/src/config/groupware.rs:133
max_ical_size: calendar.max_i_calendar_size as usize,
max_ical_instances: calendar.max_recurrence_expansions as usize,
max_ical_attendees_per_instance: calendar.max_attendees as usize,
max_vcard_size: book.max_v_card_size as usize,
vcard_version: match book.v_card_version {
RegistryVCardVersion::V3 => VCardVersion::V3_0,
RegistryVCardVersion::V4 => VCardVersion::V4_0,
},
max_file_size: file.max_size as usize,
alarms_enabled: alarm.enable,
alarms_minimum_interval: alarm.min_trigger_interval.into_inner().as_secs() as i64,
alarms_allow_external_recipients: alarm.allow_external_rcpts,
alarms_from_name: alarm.from_name,
alarms_from_email: alarm.from_email,
alarms_template: Template::parse(include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../resources/html-templates/calendar-alarm.html.min"
)))
.expect("Failed to parse calendar template"),
itip_enabled: sched.enable,
itip_auto_add: sched.auto_add_invitations,
itip_inbound_max_ical_size: sched.itip_max_size as usize,
itip_outbound_max_recipients: sched.max_recipients as usize,
itip_inbox_auto_expunge: dr
.expunge_scheduling_inbox_after
.map(|d| d.into_inner().as_secs()),
itip_http_rsvp_url: if sched.http_rsvp_enable {
if let Some(url) = sched
.http_rsvp_url
.as_deref()
.map(|v| v.trim().trim_end_matches('/'))
.filter(|v| !v.is_empty())
{
Some(url.to_string())
} else {
Some(format!("https://{}/calendar/rsvp", system.default_hostname))
}View on GitHub (pinned to e962003857)
Solutions
- Restore the pristine resources/html-templates/calendar-alarm.html.min from the upstream repository
- Regenerate the minified template with the project's official minify/build tooling instead of hand-editing
- Run Template::parse on the file in a test to pinpoint the exact syntax error
- Audit packaging steps (deb/docker) for anything rewriting or truncating resources/
- Verify a complete source checkout; include_str! requires the file at compile time
Example fix
// before (hand-edited min template with broken placeholder)
{{ alarm.start|bad_filter }}
// after (restore upstream placeholder syntax)
{{alarm.start}} {{alarm.end}} {{alarm.summary}} Defensive patterns
Strategy: validation
Validate before calling
// compile-time / CI check that the embedded template parses
#[test]
fn calendar_alarm_template_parses() {
Template::parse(include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../resources/html-templates/calendar-alarm.html.min"
))).expect("calendar-alarm template must parse");
} Try / catch
// Not catchable at runtime: it panics via .expect() during config load.
// Guard at process startup:
let config = match Config::build(...) {
Ok(c) => c,
Err(e) | Err(_) if e.to_string().contains("Failed to parse calendar template") => {
eprintln!("template resource corrupted; reinstall package");
std::process::exit(1);
}
}; Prevention
- Never hand-edit *.html.min files; always regenerate via the official minifier
- Add a unit test that parses every embedded template so breakage is caught in CI
- Verify package integrity after builds (checksum resources/ contents)
- When upgrading, re-run template minification against the current parser
When it happens
Trigger: Constructing GroupwareConfig (groupware settings enabled) where Template::parse on calendar-alarm.html.min returns Err — typically after hand-editing the minified template, running a broken minification, or a parser upgrade that rejects legacy template syntax.
Common situations: Developers editing the .min template directly and breaking placeholder syntax; build/packaging pipelines truncating files under resources/; distribution patches conflicting with a stricter template parser in a newer version; incomplete source checkouts.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to build DNSSEC resolver
- Failed to build DNS resolver
- Node id {node_id} exceeds {MAX_NODE_ID}, panicking to avoid
- Invalid system time, panicking to avoid data corruption
- unwrap_tls called on non-TLS acceptor
AI-assisted analysis of stalwartlabs/stalwart@e962003857 (2026-09-06).
Data as JSON: /api/errors/2ae749395849aae8.
Report an issue: GitHub.