{"id":"0cdfc64c5ecf314b","repo":"gohugoio/hugo","slug":"failed-to-compile-cache-buster-source-q-w","errorCode":null,"errorMessage":"failed to compile cache buster source %q: %w","messagePattern":"failed to compile cache buster source %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/commonConfig.go","lineNumber":411,"sourceCode":"\t// Trigger for files matching this regexp.\n\tSource string\n\n\t// Cache bust targets matching this regexp.\n\t// This regexp can contain group matches (e.g. $1) from the source regexp.\n\tTarget string\n\n\tcompiledSource func(string) func(string) bool\n}\n\nfunc (c *CacheBuster) CompileConfig(logger loggers.Logger) error {\n\tif c.compiledSource != nil {\n\t\treturn nil\n\t}\n\n\tsource := c.Source\n\tsourceRe, err := regexp.Compile(source)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to compile cache buster source %q: %w\", c.Source, err)\n\t}\n\ttarget := c.Target\n\tvar compileErr error\n\tdebugl := logger.Logger().WithLevel(logg.LevelDebug).WithField(loggers.FieldNameCmd, \"cachebuster\")\n\n\tc.compiledSource = func(s string) func(string) bool {\n\t\tm := sourceRe.FindStringSubmatch(s)\n\t\tmatchString := \"no match\"\n\t\tmatch := m != nil\n\t\tif match {\n\t\t\tmatchString = \"match!\"\n\t\t}\n\t\tdebugl.Logf(\"Matching %q with source %q: %s\", s, source, matchString)\n\t\tif !match {\n\t\t\treturn nil\n\t\t}\n\t\tgroups := m[1:]\n\t\tcurrentTarget := target","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/config/commonConfig.go#L393-L429","documentation":"Raised by CacheBuster.CompileConfig when the `source` field of a `build.cachebusters` entry is not a valid Go RE2 regexp. The source pattern decides which changed file triggers cache busting, and its capture groups feed `$1`-style substitutions in the target pattern; compilation happens eagerly at config load, so a bad pattern stops the build. Error 40 is the outer wrapper of this same failure.","triggerScenarios":"`hugo` or `hugo server` startup with `[[build.cachebusters]]` whose `source` fails regexp.Compile — unclosed groups/classes like `source = \"assets/watching/hugo_stats\\\\.json(\"`, PCRE-only lookarounds, or invalid escapes.","commonSituations":"Treating `source` as a glob (`**` patterns); customizing the default cachebusters (hugo_stats.json / postcss / tailwind setups) and breaking the regexp; unescaped dots or parens in file paths; TOML backslash-escaping mistakes.","solutions":["Fix the `source` regexp quoted in the error to valid RE2 syntax; close all groups and character classes.","Escape literal metacharacters, e.g. `hugo_stats\\\\.json` in TOML basic strings or use literal strings: `source = 'assets/.*\\.(js|css)$'`.","Avoid lookarounds/backreferences; restructure the pattern with alternation and anchors instead."],"exampleFix":"# before (hugo.toml)\n[[build.cachebusters]]\nsource = \"assets/.*\\\\.(js|css\"\ntarget = \"(js|css)\"\n\n# after\n[[build.cachebusters]]\nsource = 'assets/.*\\.(js|css)$'\ntarget = '(js|css)'","handlingStrategy":"validation","validationCode":"for _, cb := range cfg.Build.CacheBusters {\n    if _, err := regexp.Compile(cb.Source); err != nil {\n        return fmt.Errorf(\"build.cachebusters source %q: %w\", cb.Source, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := buildCfg.CompileConfig(logger); err != nil {\n    // names the bad [build.cachebusters].source pattern — it must be a valid RE2 regexp\n    return err\n}","preventionTips":["`source` in [[build.cachebusters]] is a regexp matched against changed file paths — escape dots (`assets/.*\\.json`)","Copy the documented defaults from gohugo.io and modify minimally","Cover config changes with a CI `hugo --logLevel info` build so compile errors surface pre-merge"],"tags":["hugo","config","regexp","cache-buster","build"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}