tauri-apps/tauri · error
Failed to setup custom handlebar template
Error message
Failed to setup custom handlebar template
What it means
Panic from `.expect("Failed to setup custom handlebar template")` in `build_wix_app_installer`. After reading the user's custom `main.wxs` template file, the bundler registers it with Handlebars; if the template contains invalid Handlebars syntax (unbalanced `{{#if}}`/`{{/if}}`, bad helpers, malformed expressions), `register_template_string` fails and the bundler panics. It is distinct from the built-in template path: the built-in `main.wxs` cannot fail, only a user-supplied one can.
Solutions
- Validate the custom template's Handlebars syntax: check every `{{#each}}`/`{{#if}}` has a matching `{{/each}}`/`{{/if}}` and escape literal `{{` as `{{{"{{"}}}` style raw blocks where needed
- Start from the built-in template shipped with your tauri-bundler version (`main.wxs` in the crate) and modify incrementally, testing after each change
- Remove or correct unsupported helper calls; only helpers registered by tauri-bundler are available in the template
- Temporarily unset `windows.wix.template` to confirm the built-in template bundles, then bisect your custom template
Example fix
// tauri.conf.json -> custom main.wxs
// before
{{#if productLanguage}}
<Product Language="en-US"/>
{{/if productLanguage}}
// after (balanced close)
{{#if productLanguage}}
<Product Language="en-US"/>
{{/if}} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-validate custom template balance before configuring it
let tpl = std::fs::read_to_string(custom_wxs_path)?;
let opens = tpl.matches("{{#").count();
let closes = tpl.matches("{{/").count();
if opens != closes {
return Err(format!(
"unbalanced handlebars blocks: {} open vs {} close",
opens, closes
));
} Try / catch
// mirror the bundler's logic locally to get a real error instead of a panic
match handlebars.register_template_string("main.wxs", tpl) {
Ok(_) => {},
Err(e) => return Err(anyhow!("invalid custom WiX template: {e}")),
} Prevention
- Start from the built-in main.wxs of your exact tauri-bundler version and edit incrementally
- After every template edit, run the bundler early to catch syntax errors fast
- Balance every {{#if}}/{{#each}} with its matching close tag
- Escape literal braces that WiX/Handlebars could misinterpret
- Keep custom templates versioned and re-diff them when upgrading Tauri
When it happens
Trigger: Providing a custom WiX template via `windows.wix.template` in tauri.conf.json (or the equivalent bundle config) whose content is not valid Handlebars syntax; the file reads fine (`fs::read_to_string` succeeded) but template compilation fails.
Common situations: Hand-edited WiX templates with mismatched block tags, copying a template from an incompatible Tauri/WiX version whose expected variables changed, missing closing braces or stray `{{` characters, or referencing unregistered helpers in the custom template.
Related errors
- Failed to setup handlebar template
- Failed to render template
- Failed to setup custom handlebar template
- Failed to setup handlebar template
- app version build number cannot be greater than 65535
AI-assisted analysis of tauri-apps/tauri@460ec35447 (2026-09-18).
Data as JSON: /api/errors/9e9602d3397cbcd9.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tauri-bundler/src/bundle/windows/msi/mod.rs:742
if let Some(file_associations) = settings.file_associations() {
data.insert("file_associations", to_json(file_associations));
}
if let Some(protocols) = settings.deep_link_protocols() {
let schemes = protocols
.iter()
.flat_map(|p| &p.schemes)
.collect::<Vec<_>>();
if !schemes.is_empty() {
data.insert("deep_link_protocols", to_json(schemes));
}
}
if let Some(path) = custom_template_path {
handlebars
.register_template_string("main.wxs", fs::read_to_string(path)?)
.map_err(|e| e.to_string())
.expect("Failed to setup custom handlebar template");
} else {
handlebars
.register_template_string("main.wxs", include_str!("./main.wxs"))
.map_err(|e| e.to_string())
.expect("Failed to setup handlebar template");
}
if enable_elevated_update_task {
data.insert(
"msiexec_args",
to_json(
settings
.updater()
.map(|updater| updater.msiexec_args)
.map(|args| args.join(" "))
.unwrap_or_else(|| "/passive".to_string()),
),
);View on GitHub (pinned to 460ec35447)