gohugoio/hugo · error

failed to compile cache buster target %q: %w

Error message

failed to compile cache buster target %q: %w

What it means

Raised inside the compiled cache-buster matcher when the `target` pattern — after substituting `$1`, `$2`... capture groups from the source match — fails regexp.Compile. Unlike the source pattern, the target is compiled lazily per match because it depends on the matched groups, so this error can appear mid-build when a matching file changes, not at config load.

Source

Thrown at config/commonConfig.go:436

		m := sourceRe.FindStringSubmatch(s)
		matchString := "no match"
		match := m != nil
		if match {
			matchString = "match!"
		}
		debugl.Logf("Matching %q with source %q: %s", s, source, matchString)
		if !match {
			return nil
		}
		groups := m[1:]
		currentTarget := target
		// Replace $1, $2 etc. in target.
		for i, g := range groups {
			currentTarget = strings.ReplaceAll(target, fmt.Sprintf("$%d", i+1), g)
		}
		targetRe, err := regexp.Compile(currentTarget)
		if err != nil {
			compileErr = fmt.Errorf("failed to compile cache buster target %q: %w", currentTarget, err)
			return nil
		}
		return func(ss string) bool {
			match := targetRe.MatchString(ss)
			matchString := "no match"
			if match {
				matchString = "match!"
			}
			logger.Debugf("Matching %q with target %q: %s", ss, currentTarget, matchString)

			return match
		}
	}
	return compileErr
}

func (r Redirect) IsZero() bool {
	return r.From == "" && r.FromRe == ""

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Fix the `target` regexp quoted in the error (the message shows the post-substitution pattern) so it compiles as RE2.
  2. If captured groups can contain regexp metacharacters, tighten the source capture group (e.g. `([\w-]+)`) so substituted values are regexp-safe.
  3. Test by touching a file matching the source pattern under `hugo server` and confirming the rebuild succeeds.

Example fix

# before (hugo.toml)
[[build.cachebusters]]
source = 'assets/js/(.*)\.js$'
target = '$1\.(js'

# after
[[build.cachebusters]]
source = 'assets/js/([\w-]+)\.js$'
target = '$1\.js'
Defensive patterns

Strategy: validation

Validate before calling

for _, cb := range cfg.Build.CacheBusters {
    if cb.Target != "" {
        if _, err := regexp.Compile(cb.Target); err != nil {
            return fmt.Errorf("build.cachebusters target %q: %w", cb.Target, err)
        }
    }
}

Try / catch

if err := buildCfg.CompileConfig(logger); err != nil {
    // "failed to compile cache buster target" — the 'target' regexp (possibly built from $1 capture substitution) is invalid
    return err
}

Prevention

When it happens

Trigger: A `[[build.cachebusters]]` `target` that is invalid RE2 on its own (e.g. unclosed group), or that becomes invalid after group substitution — e.g. the source captures a path fragment containing regexp metacharacters like `(` or `[`, and the substituted `$1` yields a broken pattern.

Common situations: Filenames or asset paths containing regexp special characters flowing into `$1` substitution; hand-written target regexps with typos that only surface when the source first matches during `hugo server` watch rebuilds; confusion that target is a regexp, not a literal replacement string.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/a52d9d52c5927b35.json. Report an issue: GitHub ↗.