amir20/dozzle · error
failed to execute template
Error message
failed to execute template: %w
What it means
executeJSONTemplate builds a Go text/template from the user-provided webhook JSON template and executes it against the notification data. This error is returned when template.Parsed content fails at execution time (tmpl.Execute returns an error), e.g. when the template references a field or function not present in the data map, or an invokable value is not a function. Parsing succeeded but rendering did not, so the webhook payload could not be produced.
Solutions
- Check the wrapped execErr (the %w cause) to see which field or function the template referenced that does not exist.
- Correct the template placeholders so every {{ .Field }} matches a key in the notification data structure.
- Remove or replace calls to undefined template functions; only built-in text/template funcs are available.
- Validate the template by sending a test notification (SendTest) before saving it to production config.
Example fix
// before (template references a field that doesn't exist)
{"text": "Container {{ .ContainerNamee }} failed"}
// after
{"text": "Container {{ .ContainerName }} failed"} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check: every referenced field exists in data
for field := range referencedFields(templateText) {
if _, ok := data[field]; !ok {
return fmt.Errorf("template references missing field %q", field)
}
} Try / catch
payload, err := executeJSONTemplate(structure, data)
if err != nil {
var wrapped *fmt.WrapError
if errors.As(err, &templateExecErr{}) {
log.Printf("fix webhook template placeholders: %v", err)
}
return fmt.Errorf("webhook not sent: %w", err)
} Prevention
- Keep a documented list of available data fields next to the webhook config.
- Always run SendTest after editing a template.
- Avoid deep optional paths unless guarded with {{ if }}.
When it happens
Trigger: A webhook dispatcher template contains {{ ... }} actions referencing missing keys in the data map (e.g. {{ .NonExistentField }}), calls a nonexistent template function, or invokes a non-function value. Triggered via SendTest and the other executeJSONTemplate callers (tests: TestExecuteJSONTemplate_EscapesQuotes, _EscapesNewlines, _EscapesBackslashes, _MultiplePlaceholders, _NestedObjects).
Common situations: Users hand-edit the webhook template in the notification UI and typo a field name, use Go pipeline syntax the data doesn't satisfy, or reference keys that were renamed in a newer Dozzle version.
Related errors
- failed to execute template field
- Failed to save destination
- failed to parse template
- webhook notification failed
- failed to parse template field
AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07).
Data as JSON: /api/errors/21dda8d497ebc9cd.
Report an issue: GitHub.
Appendix: source
Thrown at internal/notification/dispatcher/webhook.go:286
}
return TestResult{Success: true, StatusCode: resp.StatusCode}
}
// executeJSONTemplate parses the template as JSON, resolves Go template placeholders
// in string values, and marshals back to JSON. This ensures all values are properly
// JSON-escaped regardless of their content (e.g., log messages containing quotes or braces).
func executeJSONTemplate(templateText string, data any) ([]byte, error) {
var structure any
if err := json.Unmarshal([]byte(templateText), &structure); err != nil {
// Not valid JSON — fall back to raw text/template execution
tmpl, parseErr := template.New("webhook").Parse(templateText)
if parseErr != nil {
return nil, fmt.Errorf("failed to parse template: %w", parseErr)
}
var buf bytes.Buffer
if execErr := tmpl.Execute(&buf, data); execErr != nil {
return nil, fmt.Errorf("failed to execute template: %w", execErr)
}
return buf.Bytes(), nil
}
resolved, err := resolveTemplateValues(structure, data)
if err != nil {
return nil, err
}
return json.Marshal(resolved)
}
// resolveTemplateValues recursively walks a JSON structure and executes
// Go template expressions found in string values.
func resolveTemplateValues(v any, data any) (any, error) {
switch val := v.(type) {
case map[string]any:
result := make(map[string]any, len(val))View on GitHub (pinned to d9463cbe21)