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

  1. Clone before the first Execute on the template or any associated template.
  2. Keep an unexecuted master template and always clone from it; execute only the clones.
  3. Rebuild with New + Parse instead of cloning when the template is already executed.
  4. 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

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


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/92d088dcb244c633. Report an issue: GitHub.