gohugoio/hugo · error

unrecognized render hook template

Error message

unrecognized render hook template

What it means

Hugo categorizes templates under layouts/_markup/ as render-hook templates (CategoryMarkup). When extracting the template key (templatestore.go:1895-1901), it requires the layout name to begin with 'render-' (e.g. render-link, render-image) and uses strings.CutPrefix to split it off. If the prefix is absent, the template is not a recognized render hook and the error is returned. This catches misnamed files placed in the _markup directory.

Solutions

  1. Rename the file so it starts with 'render-', e.g. render-link.html, render-image.html, render-heading.html.
  2. If the file is not a render hook, move it out of the _markup directory (e.g. to layouts/partials/).
  3. Verify the filename against supported hooks: render-link, render-image, render-heading, render-codeblock, etc.

Example fix

// before
layouts/_markup/link.html

// after
layouts/_markup/render-link.html
Defensive patterns

Strategy: validation

Validate before calling

// Before adding a file under layouts/_markup/, confirm its name starts with 'render-'
// Supported: render-link.html, render-image.html, render-heading.html,
//            render-codeblock-*.html, etc.
// If it's not a render hook, place it under layouts/partials/ instead.

Prevention

When it happens

Trigger: Placing a template file in layouts/_markup/ (or a theme equivalent) whose filename does not start with 'render-', e.g. layouts/_markup/link.html or layouts/_markup/foo.html. Encountered during template ingestion/key extraction.

Common situations: Misunderstanding the render-hook naming convention; renaming a render-link.html to something else; placing a non-render-hook helper template in _markup by mistake; old tutorials referencing pre-render-hook era filenames.

Related errors


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

Appendix: source

Thrown at tpl/tplimpl/templatestore.go:1900

		}
		d.LayoutFromTemplate = ""
	}

	if d.LayoutFromTemplate == d.Kind {
		d.LayoutFromTemplate = ""
	}

	k1 = strings.TrimPrefix(k1, "/_default")
	if k1 == "/" {
		k1 = ""
	}

	if category == CategoryMarkup {
		// We store all template nodes for a given directory on the same level.
		k1 = strings.TrimSuffix(k1, "/_markup")
		v, found := strings.CutPrefix(d.LayoutFromTemplate, "render-")
		if !found {
			return "", "", 0, TemplateDescriptor{}, nil, fmt.Errorf("unrecognized render hook template")
		}
		hyphenIdx := strings.Index(v, "-")

		d.Variant1 = v
		if hyphenIdx > 0 {
			d.Variant1 = v[:hyphenIdx]
			d.Variant2 = v[hyphenIdx+1:]
		}

		d.LayoutFromTemplate = "" // This allows using page layout as part of the key for lookups.
	}

	return k1, k2, category, d, vactorStore, nil
}

func (s *TemplateStore) transformTemplates() error {
	lookup := func(name string, in *TemplInfo) *TemplInfo {
		if in.D.IsPlainText {

View on GitHub (pinned to 52c9bd7908)