gohugoio/hugo · error

: template for shortcode not found

Error message

%s: template for shortcode %q not found

What it means

Raised in extractShortcode (shortcode.go:671) during the parsing of a shortcode name token: s.firstTemplateStore.LookupShortcodeByName returns nil, meaning no shortcode template with that name is registered in any template store reachable from the page. This fires at parse time, before rendering, while Hugo decides whether the shortcode expects inner content.

Solutions

  1. Create layouts/shortcodes/<name>.html (or .amber/.ace per your template engine) in the project or theme.
  2. Correct the shortcode name in the content to match an existing template exactly (case-sensitive).
  3. Ensure the theme providing the shortcode is listed under `theme`/`module.imports` and mounted.

Example fix

{{/* before: no such shortcode */}}
{{< greeeting >}}

{{/* after */}}
{{< greeting >}}
# and create layouts/shortcodes/greeting.html
Defensive patterns

Strategy: validation

Validate before calling

# Verify every shortcode name used in content has a template.
used=$(grep -rhoE '\{\{[%<][[:space:]]*[a-zA-Z0-9_-]+' content | sed -E 's/.*[[:space:]]+//' | sort -u)
for name in $used; do
  find layouts -path "*/shortcodes/${name}.html" | grep -q . || echo "missing shortcode template: $name"
done

Prevention

When it happens

Trigger: Using {{< foo >}} when no layouts/shortcodes/foo.html (or theme equivalent) exists; a typo in the shortcode name; the shortcode lives only in a theme that is not mounted; output-format/language mismatch so the lookup set excludes the only defining template.

Common situations: Switching themes and forgetting to migrate custom shortcodes; content referencing a shortcode that was renamed/removed; theme not added to hugo.toml; shortcode names with case differences (shortcode names are case-sensitive in lookup).

Related errors


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

Appendix: source

Thrown at hugolib/shortcode.go:671

			if next.IsRightShortcodeDelim() {
				// self-closing
				pt.Consume(1)
			} else {
				sc.isClosing = true
				pt.Consume(2)
			}
			return sc, nil
		case currItem.IsText():
			sc.inner = append(sc.inner, currItem.ValStr(source))
		case currItem.IsShortcodeName():

			sc.name = currItem.ValStr(source)

			// Used to check if the template expects inner content,
			// so just pick one arbitrarily with the same name.
			templ := s.firstTemplateStore.LookupShortcodeByName(sc.name)
			if templ == nil {
				return nil, fmt.Errorf("%s: template for shortcode %q not found", errorPrefix, sc.name)
			}
			sc.templ = templ
		case currItem.IsInlineShortcodeName():
			sc.name = currItem.ValStr(source)
			sc.isInline = true
		case currItem.IsShortcodeParam():
			if !pt.IsValueNext() {
				continue
			} else if pt.Peek().IsShortcodeParamVal() {
				// named params
				if sc.params == nil {
					params := make(map[string]any)
					params[currItem.ValStr(source)] = pt.Next().ValTyped(source)
					sc.params = params
				} else {
					if params, ok := sc.params.(map[string]any); ok {
						params[currItem.ValStr(source)] = pt.Next().ValTyped(source)
					} else {

View on GitHub (pinned to 52c9bd7908)