gohugoio/hugo · error
html/template: cannot Clone %q after it has executed
Error message
html/template: cannot Clone %q after it has executed
What it means
Returned by html/template Clone (the full clone) at its initial guard: if t.escapeErr is non-nil (template was already escaped/executed), Clone refuses. Cloning an escaped template would duplicate frozen escaping state into a fresh nameSpace that expects unescaped input, so it is disallowed. The %q is t.Name().
Source
Thrown at tpl/internal/go_templates/htmltemplate/template.go:251
t.nameSpace,
}
t.set[name] = ret
return ret, nil
}
// Clone returns a duplicate of the template, including all associated
// templates. The actual representation is not copied, but the name space of
// associated templates is, so further calls to [Template.Parse] in the copy will add
// templates to the copy but not to the original. [Template.Clone] can be used to prepare
// common templates and use them with variant definitions for other templates
// by adding the variants after the clone is made.
//
// It returns an error if t has already been executed.
func (t *Template) Clone() (*Template, error) {
t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock()
if t.escapeErr != nil {
return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name())
}
textClone, err := t.text.Clone()
if err != nil {
return nil, err
}
ns := &nameSpace{set: make(map[string]*Template)}
ns.esc = makeEscaper(ns)
ret := &Template{
nil,
textClone,
textClone.Tree,
ns,
}
ret.set[ret.Name()] = ret
for _, x := range textClone.Templates() {
name := x.Name()
src := t.set[name]
if src == nil || src.escapeErr != nil {View on GitHub (pinned to 52c9bd7908)
Solutions
- Clone before the first Execute on the template or any associated template.
- Keep an unexecuted master template and always clone from it; execute only the clones.
- Rebuild with New + Parse instead of cloning when the template is already executed.
- Reorder init code so cloning precedes any rendering.
Example fix
// before
t.Execute(w, data)
clone, err := t.Clone() // error
// after
clone, err := t.Clone() // clone first
if err != nil { return err }
t.Execute(w, data) Defensive patterns
Strategy: validation
Validate before calling
// Maintain a master (unexecuted) template for cloning.
var masterT *template.Template
func variant() (*template.Template, error) {
if masterT == nil {
return nil, fmt.Errorf("master not initialized")
}
return masterT.Clone() // always clone the unexecuted master
} Try / catch
clone, err := t.Clone()
if err != nil {
if strings.Contains(err.Error(), "cannot Clone") {
// rebuild a fresh master instead of cloning an executed one
master := template.New(t.Name())
if _, perr := master.Parse(masterBody); perr != nil { return nil, perr }
return master.Clone()
}
return nil, err
} Prevention
- Keep an unexecuted master; execute only clones.
- Clone once at setup before any render.
- Treat execution as a one-way transition for a given set.
When it happens
Trigger: Calling (*htmltemplate.Template).Clone() on a Template whose escapeErr is set by a prior Execute/ExecuteTemplate/Prepare on it (escapeErr != nil and != escapeOK).
Common situations: Building per-request template variants by cloning after a warm-up render; reusing a base template that was already executed in a previous request; server code that executes then clones the same shared instance.
Related errors
- html/template: cannot Clone %q after it has executed
- html/template: cannot Parse after Execute
- template: %q is an incomplete or empty template
- html/template: %q is undefined
- html/template: %q is an incomplete template
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/92d088dcb244c633.
Report an issue: GitHub.