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

  1. Check the wrapped execErr (the %w cause) to see which field or function the template referenced that does not exist.
  2. Correct the template placeholders so every {{ .Field }} matches a key in the notification data structure.
  3. Remove or replace calls to undefined template functions; only built-in text/template funcs are available.
  4. 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

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


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)