knadh/listmonk · error

error compiling subject: %v

Error message

error compiling subject: %v

What it means

This error is returned by Template.Compile in models/templates.go when the template's Subject contains template expressions (hasTplExpr detects {{ ... }}) that fail to parse as a Go text/template. The subject is compiled separately from the body with txttpl.New(BaseTpl).Funcs(txttpl.FuncMap(f)).Parse so it can be rendered per-message; a parse failure is wrapped as "error compiling subject: %v". Only tx templates with templated subjects reach this path.

Source

Thrown at models/templates.go:53

	Attachments []Attachment       `json:"-"`
}

// Compile compiles a template body and subject (only for tx templates) and
// caches the templat references to be executed later.
func (t *Template) Compile(f template.FuncMap) error {
	tpl, err := template.New(BaseTpl).Funcs(f).Parse(t.Body)
	if err != nil {
		return fmt.Errorf("error compiling transactional template: %v", err)
	}
	t.Tpl = tpl

	// If the subject line has a template string, compile it.
	if hasTplExpr(t.Subject) {
		subj := t.Subject

		subjTpl, err := txttpl.New(BaseTpl).Funcs(txttpl.FuncMap(f)).Parse(subj)
		if err != nil {
			return fmt.Errorf("error compiling subject: %v", err)
		}
		t.SubjectTpl = subjTpl
	}

	return nil
}

type CampaignStats struct {
	ID        int       `db:"id" json:"id"`
	Status    string    `db:"status" json:"status"`
	ToSend    int       `db:"to_send" json:"to_send"`
	Sent      int       `db:"sent" json:"sent"`
	Started   null.Time `db:"started_at" json:"started_at"`
	UpdatedAt null.Time `db:"updated_at" json:"updated_at"`
	Rate      int       `json:"rate"`
	NetRate   int       `json:"net_rate"`
}

View on GitHub (pinned to 670c01717d)

Solutions

  1. Fix the subject template syntax named in the wrapped parse error (balance braces, close all actions, correct end tags).
  2. Ensure every function used in the subject exists in the FuncMap passed to Compile.
  3. If the subject needs no per-message templating, remove {{ }} expressions so it is stored and used literally.
  4. Validate the subject with text/template.Parse in a quick standalone test before saving the template.
  5. Audit existing subject lines after upgrading the library in case available template functions changed.

Example fix

// before
t.Subject = "Receipt for {{ .Subscriber.Name "
// after
t.Subject = "Receipt for {{ .Subscriber.Name }}"
Defensive patterns

Strategy: validation

Validate before calling

import ("strings" "text/template")

func validateTemplateSubject(subject string, funcs template.FuncMap) error {
	if subject == "" || !strings.Contains(subject, "{{") {
		return nil
	}
	_, err := template.New("subject").Funcs(funcs).Parse(subject)
	return err
}

Type guard

func subjectIsTemplated(subject string) bool {
	return strings.Contains(subject, "{{") && strings.Contains(subject, "}}")
}

Try / catch

if err := tpl.Compile(funcs); err != nil {
	if strings.HasPrefix(err.Error(), "error compiling subject") {
		return fmt.Errorf("template subject is not valid Go text/template syntax: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling CreateTemplate/UpdateTemplate (or previewTemplate/CacheTpl) on a Template whose Subject is non-empty, contains {{ ... }}, and is syntactically invalid — unclosed action, unknown function name, malformed pipeline, or unbalanced braces.

Common situations: Typo in a custom template function inside the subject line, pasting HTML-template pipelines valid only in html/template, stray braces from hand editing the subject in the admin UI, removing/renaming a FuncMap function that existing subject lines still reference.

Related errors


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