knadh/listmonk · error

error compiling alt body: %v

Error message

error compiling alt body: %v

What it means

This error comes from TxMessage.Render in models/messages.go when the message's plain-text AltBody contains template expressions ({{ ... }}) that fail to PARSE against Go's text/template engine. Render compiles AltBody as its own txttemplate before executing it; a parse failure (bad syntax, unknown function, unclosed action) is wrapped as "error compiling alt body: %v". It is a compile-time template syntax problem, not a rendering/execution failure.

Source

Thrown at models/messages.go:96

	data := struct {
		Subscriber Subscriber
		Tx         *TxMessage
	}{sub, m}

	// Render the body.
	b := bytes.Buffer{}
	if err := tpl.Tpl.ExecuteTemplate(&b, BaseTpl, data); err != nil {
		return err
	}
	m.Body = make([]byte, b.Len())
	copy(m.Body, b.Bytes())
	b.Reset()

	// Render alt body if it has any templating strings.
	if m.AltBody != "" && hasTplExpr(m.AltBody) {
		t, err := txttpl.New(BaseTpl).Funcs(funcs).Parse(m.AltBody)
		if err != nil {
			return fmt.Errorf("error compiling alt body: %v", err)
		}
		if err := t.ExecuteTemplate(&b, BaseTpl, data); err != nil {
			return err
		}
		m.AltBody = b.String()
		b.Reset()
	}

	// Was a subject provided in the message?
	var (
		subjTpl *txttpl.Template
		subject = m.Subject
	)
	if subject != "" {
		if hasTplExpr(m.Subject) {
			// If the subject has a template string, render that.
			s, err := txttpl.New(BaseTpl).Funcs(funcs).Parse(m.Subject)
			if err != nil {

View on GitHub (pinned to 670c01717d)

Solutions

  1. Fix the template syntax in TxMessage.AltBody reported in the wrapped error (unbalanced {{ }}, bad pipeline, missing end tag).
  2. Verify every function used in AltBody exists in the FuncMap passed to Render (from the campaign/messenger template funcs).
  3. If the alt body has no templating needs, remove {{ }} expressions entirely — Render only compiles AltBody when hasTplExpr() detects template strings.
  4. Test the alt body with text/template.Parse in a scratch Go program to reproduce and isolate the parse error.
  5. Check for html/template-specific constructs ({{ define }} with context escaping, URL filters) that text/template may not accept as written.

Example fix

// before
m.AltBody = "Hi {{ .Subscriber.Name }}, your total is {{ .Tx.Amount }"
// after
m.AltBody = "Hi {{ .Subscriber.Name }}, your total is {{ .Tx.Amount }}"
Defensive patterns

Strategy: validation

Validate before calling

import ("strings" "text/template")

func validateAltBody(altBody string, funcs template.FuncMap) error {
	if !strings.Contains(altBody, "{{") {
		return nil // no template expression, Render won't compile it
	}
	_, err := template.New("alt").Funcs(funcs).Parse(altBody)
	return err
}

Type guard

func isTemplated(s string) bool {
	return strings.Contains(s, "{{") && strings.Contains(s, "}}")
}

Try / catch

if err := msg.Render(sub, tpl, funcs); err != nil {
	if strings.HasPrefix(err.Error(), "error compiling alt body") {
		log.Errorf("alt body template syntax invalid: %v", err)
		// fall back to the raw AltBody or a static default, or reject the send
		return fmt.Errorf("rejecting tx message: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling SendTxMessage (or previewTemplate) with a TxMessage whose AltBody contains {{ ... }} template strings that are syntactically invalid — e.g. {{ .Tx.AltBody }}} with an extra brace, {{ .Subscriber.Name | titlexx }} referencing a func missing from the provided FuncMap, or an unclosed {{ if }} block.

Common situations: Hand-written alt bodies with stray braces (e.g. CSS/JS snippets inside the text part), typos in template function names registered in the FuncMap, copying HTML template syntax (html/template pipelines) into the text part, or an upgrade changing the available template functions.

Related errors


AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01). Data as JSON: /api/errors/388e5e9da7fb8713. Report an issue: GitHub.