knadh/listmonk · error
template %d not found
Error message
template %d not found
What it means
GetTpl looks up a compiled template by numeric ID from the manager's in-memory template cache under a read lock. If no template with that ID is cached, this error is returned. It means the template either never existed, was deleted, or hasn't been loaded into the manager's cache yet.
Source
Thrown at internal/manager/manager.go:363
m.tpls[id] = tpl
m.tplsMut.Unlock()
}
// DeleteTpl deletes a cached template.
func (m *Manager) DeleteTpl(id int) {
m.tplsMut.Lock()
delete(m.tpls, id)
m.tplsMut.Unlock()
}
// GetTpl returns a cached template.
func (m *Manager) GetTpl(id int) (*models.Template, error) {
m.tplsMut.RLock()
tpl, ok := m.tpls[id]
m.tplsMut.RUnlock()
if !ok {
return nil, fmt.Errorf("template %d not found", id)
}
return tpl, nil
}
// TemplateFuncs returns the template functions to be applied into
// compiled campaign templates.
func (m *Manager) TemplateFuncs(c *models.Campaign) template.FuncMap {
f := template.FuncMap{
"TrackLink": func(url string, msg *CampaignMessage) string {
if m.cfg.DisableTracking {
return url
}
subUUID := msg.Subscriber.UUID
if !m.cfg.IndividualTracking {
subUUID = dummyUUID
}View on GitHub (pinned to 670c01717d)
Solutions
- Verify the template ID exists (query the templates table / admin UI) and correct the reference
- Re-load or refresh the manager's template cache (re-init or reload) so deleted/renamed templates are reflected
- Repoint the campaign or code to an existing template ID
- Ensure initialization order: load templates before starting the campaign scanner that may call GetTpl
Example fix
// before
tpl, err := m.GetTpl(42) // stale id from deleted template
// after
id, err := resolveTemplateIDByName("welcome-email")
if err != nil { return err }
tpl, err := m.GetTpl(id) Defensive patterns
Strategy: try-catch
Validate before calling
// Confirm the template exists before rendering a campaign
if !templateExistsInStore(templateID) {
return fmt.Errorf("template %d does not exist; repoint campaign to a valid template", templateID)
} Try / catch
tpl, err := mgr.GetTpl(id)
if err != nil {
if strings.Contains(err.Error(), "not found") {
tpl, err = loadFallbackTemplate(mgr)
}
if err != nil { return err }
} Prevention
- Never delete templates still referenced by campaigns; check references first
- Warm the template cache before starting the campaign scanner
- Store template references by resolvable name where possible and resolve at send time
- After DB restores/imports, verify template IDs match campaigns
When it happens
Trigger: Requesting a campaign/template render with a template ID that was deleted (campaign still referencing it), an ID from another installation/database, or calling GetTpl before the manager finished loading templates from the store.
Common situations: Stale campaign rows pointing at removed templates, race at startup where a campaign scan runs before template cache warm-up completes, hardcoded template IDs in scripts/tests after DB resets, or importing data without templates.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- campaigns.fieldInvalidSubject
- campaigns.fieldInvalidBody
- campaigns.fieldInvalidName
- error fetching attachment %d on campaign %s: %v
- error rendering header %q: %v
AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01).
Data as JSON: /api/errors/80ed9291483c356f.
Report an issue: GitHub.