crowdsecurity/crowdsec · error
parse challenge html template: %w
Error message
parse challenge html template: %w
What it means
NewChallengeRuntime parses the built-in challenge HTML/JS template with text/template once at startup and wraps parse failures with 'parse challenge html template'. Since htmlTemplate is hardcoded in the source, this only fires if the template text was modified and became syntactically invalid ({{ }} imbalance, bad actions).
Source
Thrown at pkg/appsec/challenge/challenge.go:465
}
// No need to keep the closer around, we can just close the runtime itself when stopping
if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
return nil, fmt.Errorf("failed to instantiate WASI: %w", err)
}
compiledMod, err := compileObfuscatorModule(ctx, r)
if err != nil {
return nil, err
}
// We use text/template instead of html/template because the data we send
// is pretty much hardcoded and trusted; html/template would escape the JS
// we inject. Parsed once here so GetChallengePage doesn't re-parse on
// every request.
htmlTpl, err := template.New("challenge").Parse(htmlTemplate)
if err != nil {
return nil, fmt.Errorf("parse challenge html template: %w", err)
}
challengeRuntime := &ChallengeRuntime{
r: r,
obfuscatorMod: compiledMod,
powDifficulty: defaultPowDifficulty,
keys: keys,
cryptoPoolSize: cryptoPoolSize,
dynamicModuleCache: make(map[int64][]string),
cookieTTL: cookieTTL,
maxCookieLen: maxCookieLen,
htmlTpl: htmlTpl,
spent: newSpentSet(spentSetMaxEntries),
logger: logger,
}
// Load the build-time-obfuscated challenge code from the baked-in bundle so
// we can serve immediately.View on GitHub (pinned to 909b515798)
Solutions
- Revert htmlTemplate in challenge.go to the upstream version (git checkout -- pkg/appsec/challenge/challenge.go).
- If customizing, validate the template offline: template.Must(template.New("challenge").Parse(yourHTML)) in a scratch test.
- Escape literal braces in JS/CSS with {{"{"}} or use a custom delimiter set ({{ "{" }} or template.New(...).Delims).
- Run go test ./pkg/appsec/challenge/... to catch parse failures at build time.
Example fix
// before (invalid literal braces in JS)
for (let i = 0; i < {{.MaxIter}}; i++) { hash() }
// after
for (let i = 0; i < {{.MaxIter}}; i++) {{"{"}} hash() {{"}"}} Defensive patterns
Strategy: validation
Validate before calling
// Validate template parseability at build/test time
_, err := template.New("challenge").Parse(htmlTemplate)
if err != nil {
return fmt.Errorf("embedded challenge template invalid: %w", err)
} Try / catch
htmlTpl, err := template.New("challenge").Parse(htmlTemplate)
if err != nil { return nil, fmt.Errorf("parse challenge html template: %w", err) } // the wrapped error gives line/col of the bad action Prevention
- Escape literal braces in embedded JS/CSS with {{"{"}} / {{"}"}}
- Add a parse test for the embedded template so edits fail in CI
- Use template.Must for compile-time safety in fork variants
When it happens
Trigger: NewChallengeRuntime -> template.New("challenge").Parse(htmlTemplate) fails: the embedded htmlTemplate constant was edited (fork, patch, generated variant) and contains invalid template syntax.
Common situations: Rebranding/customizing the challenge page in a fork with mismatched {{...}} delimiters; code-generation mistakes altering the template string.
Related errors
- failed to compile profiles: %w
- failed to create gzip reader for obfuscator wasm: %w
- failed to decompress obfuscator wasm: %w
- failed to compile obfuscator wasm module: %w
- pid inside tag must be closed with ']'
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/bc34b2060e974bb7.
Report an issue: GitHub.