{"record":{"id":"a8dd663f813a11d8","repo":"knadh/listmonk","slug":"error-compiling-transactional-template-v","errorCode":null,"errorMessage":"error compiling transactional template: %v","messagePattern":"error compiling transactional template: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"models/templates.go","lineNumber":43,"sourceCode":"\t// Subject is only for type=tx.\n\tSubject    string      `db:\"subject\" json:\"subject\"`\n\tType       string      `db:\"type\" json:\"type\"`\n\tBody       string      `db:\"body\" json:\"body,omitempty\"`\n\tBodySource null.String `db:\"body_source\" json:\"body_source,omitempty\"`\n\tIsDefault  bool        `db:\"is_default\" json:\"is_default\"`\n\n\t// Only relevant to tx (transactional) templates.\n\tSubjectTpl  *txttpl.Template   `json:\"-\"`\n\tTpl         *template.Template `json:\"-\"`\n\tAttachments []Attachment       `json:\"-\"`\n}\n\n// Compile compiles a template body and subject (only for tx templates) and\n// caches the templat references to be executed later.\nfunc (t *Template) Compile(f template.FuncMap) error {\n\ttpl, err := template.New(BaseTpl).Funcs(f).Parse(t.Body)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error compiling transactional template: %v\", err)\n\t}\n\tt.Tpl = tpl\n\n\t// If the subject line has a template string, compile it.\n\tif hasTplExpr(t.Subject) {\n\t\tsubj := t.Subject\n\n\t\tsubjTpl, err := txttpl.New(BaseTpl).Funcs(txttpl.FuncMap(f)).Parse(subj)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error compiling subject: %v\", err)\n\t\t}\n\t\tt.SubjectTpl = subjTpl\n\t}\n\n\treturn nil\n}\n\ntype CampaignStats struct {","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/knadh/listmonk/blob/670c01717d48647093335cc23a6be6f4b79c3b6b/models/templates.go#L25-L61","documentation":"This error is returned by Template.Compile in models/templates.go when the template's Body fails to parse as a Go html/template. Compile is invoked whenever a (transactional) template is created or updated (CreateTemplate, UpdateTemplate), previewed (previewTemplate), or cached (CacheTpl). The wrapped %v is the underlying template parse error (bad syntax, unclosed actions, undefined functions registered in the FuncMap).","triggerScenarios":"Calling CreateTemplate/UpdateTemplate with a template whose Body contains invalid html/template syntax — unclosed {{ if }}/{{ range }} blocks, stray {{ or }} characters in content, an unknown function in a pipeline not present in the FuncMap f, or malformed {{ define }}/{{ block }} structures.","commonSituations":"Users paste HTML with literal curly braces (CSS, JS snippets like `{{ x }}` in code samples) that the parser interprets as template actions; copy-pasting templates from other engines (Jinja2/Liquid) with incompatible syntax; a template function was removed or renamed so pipelines referencing it fail at parse-registered-func lookup; unbalanced tags after hand edits in the admin UI.","solutions":["Read the wrapped parse error and fix the offending line in Template.Body — usually an unclosed {{ }}, missing {{ end }}, or stray brace.","Escape any literal {{ or }} in content (e.g. in CSS/JS snippets) as \"{{\" \"}}\" or restructure so the parser does not treat them as actions.","Verify all functions used in the body exist in the FuncMap passed to Compile; register missing ones before CreateTemplate/UpdateTemplate.","If migrating from another templating engine, convert its syntax (e.g. Jinja {% if %}, Liquid {% for %}) to Go template equivalents ({{ if }}, {{ range }}).","Re-test by calling previewTemplate with sample data once the body parses."],"exampleFix":"// before\nbody := \"Hi {{ .Subscriber.Name }, you have {{ range .Tx.Items }}item{{ end\"\n// after\nbody := \"Hi {{ .Subscriber.Name }}, you have {{ range .Tx.Items }}item{{ end }}\"","handlingStrategy":"validation","validationCode":"import \"html/template\"\n\nfunc validateTemplateBody(body string, funcs template.FuncMap) error {\n\t_, err := template.New(\"body\").Funcs(funcs).Parse(body)\n\treturn err\n}\n// Call before POST/PUT to the templates API; if it returns an error, fix the body first.","typeGuard":null,"tryCatchPattern":"if err := tpl.Compile(funcs); err != nil {\n\tif strings.HasPrefix(err.Error(), \"error compiling transactional template\") {\n\t\treturn fmt.Errorf(\"template body is not valid Go template syntax: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Validate the body with html/template.Parse server-side before saving (exactly what Compile does).","Escape literal {{ }} appearing in CSS/JS content as {{\"{{\"}} / {{\"}}\"}}.","Convert syntax from other engines (Jinja/Liquid) before pasting into the template editor.","Keep the template FuncMap stable; document and deprecate functions instead of removing them.","Use previewTemplate with sample data as part of the save workflow to catch breakage early."],"tags":["go","html-template","template-syntax","compilation"],"backgroundTag":"template-syntax-error","analyzedSha":"670c01717d48647093335cc23a6be6f4b79c3b6b","analyzedAt":"2026-09-01T03:39:35.452Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}