knadh/listmonk · error

campaigns.fieldInvalidBody

Error message

campaigns.fieldInvalidBody

What it means

validateCampaignFields compiles the campaign body as a Go template via c.CompileTemplate(a.manager.TemplateFuncs(&camp)); any template parse/compile failure becomes campaigns.fieldInvalidBody with the underlying error interpolated. It guards against invalid template syntax or references to undefined template functions.

Source

Thrown at cmd/campaigns.go:733

		}
	}

	if len(c.ListIDs) == 0 {
		return c, errors.New(a.i18n.T("campaigns.fieldInvalidListIDs"))
	}

	if !a.manager.HasMessenger(c.Messenger) {
		// If it's a specific SMTP, but it's no longer available (removed/disabled), fall back to general email messenger.
		if strings.HasPrefix(c.Messenger, "email-") {
			c.Messenger = "email"
		} else {
			return c, errors.New(a.i18n.Ts("campaigns.fieldInvalidMessenger", "name", c.Messenger))
		}
	}

	camp := models.Campaign{Body: c.Body, TemplateBody: tplTag}
	if err := c.CompileTemplate(a.manager.TemplateFuncs(&camp)); err != nil {
		return c, errors.New(a.i18n.Ts("campaigns.fieldInvalidBody", "error", err.Error()))
	}

	if len(c.Headers) == 0 {
		c.Headers = make([]map[string]string, 0)
	}

	// Validate and initialize attribs.
	if c.Attribs != nil {
		if _, err := json.Marshal(c.Attribs); err != nil {
			return c, errors.New(a.i18n.T("subscribers.invalidJSON"))
		}
	}

	if len(c.ArchiveMeta) == 0 {
		c.ArchiveMeta = json.RawMessage("{}")
	}

	if c.ArchiveSlug.String != "" {

View on GitHub (pinned to 670c01717d)

Solutions

  1. Fix the template syntax reported in the interpolated error message — typically an unclosed {{ }} or bad expression.
  2. Escape literal braces not meant as templates (e.g. use {{ "{{" }} or avoid them) in CSS/JS or Angular-style code.
  3. Replace unknown function calls with ones registered in TemplateFuncs (e.g. use built-in newsletter functions).
  4. Compile the body locally with text/template and the same func map to reproduce the exact parse error before submitting.

Example fix

// before
{"body": "<div ng-if="{{user.active}}">Hi</div>"}
// after
{"body": "<div data-active="{{ if .Subscriber.Status }}1{{ end }}">Hi</div>"}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-compile the body with Go's text/template rules before calling the API
// (in Go)
_, err := template.New("body").Funcs(myFuncs).Parse(campaignBody)
if err != nil {
    return fmt.Errorf("campaign body template error: %w", err)
}

Try / catch

try {
  await api.createCampaign({ body, ...rest });
} catch (e) {
  if (e.message.includes('fieldInvalidBody')) {
    // e.message embeds the underlying Go template error
    throw new Error(`Fix campaign body template: ${e.message}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Campaign body containing malformed Go template syntax (unclosed {{ }}, bad pipelines) or calling template functions that don't exist in the manager's TemplateFuncs, on create/update/test campaign calls.

Common situations: Pasting HTML with stray '{{' characters (e.g. CSS/JS or Angular/Vue bindings) that Go templates try to parse; typos in custom template function names; template tags from another system (Handlebars {{#if}}) used verbatim.

Related errors


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