{"id":"da5518274d8d085e","repo":"gohugoio/hugo","slug":"id-must-not-contain-backslashes","errorCode":null,"errorMessage":"id must not contain backslashes","messagePattern":"id must not contain backslashes","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/esbuild/batch.go","lineNumber":158,"sourceCode":"\nfunc (o *optsHolder[C]) SetOptions(m map[string]any) string {\n\to.optsSetCounter++\n\to.optsPrev = o.optsCurr\n\to.optsCurr = m\n\to.compiledPrev = o.compiled\n\to.compiled, o.compileErr = o.compiled.compileOptions(m, o.defaults)\n\to.checkCompileErr()\n\treturn \"\"\n}\n\n// ValidateBatchID validates the given ID according to some very\nfunc ValidateBatchID(id string, isTopLevel bool) error {\n\tif id == \"\" {\n\t\treturn fmt.Errorf(\"id must be set\")\n\t}\n\t// No Windows slashes.\n\tif strings.Contains(id, \"\\\\\") {\n\t\treturn fmt.Errorf(\"id must not contain backslashes\")\n\t}\n\n\t// Allow forward slashes in top level IDs only.\n\tif !isTopLevel && strings.Contains(id, \"/\") {\n\t\treturn fmt.Errorf(\"id must not contain forward slashes\")\n\t}\n\n\treturn nil\n}\n\nfunc newIsBuiltOrTouched() isBuiltOrTouched {\n\treturn isBuiltOrTouched{\n\t\tbuilt:   make(buildIDs),\n\t\ttouched: make(buildIDs),\n\t}\n}\n\nfunc newOpts[K any, C optionsCompiler[C]](key K, optionsID string, defaults defaultOptionValues) *opts[K, C] {","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/internal/js/esbuild/batch.go#L140-L176","documentation":"Batch IDs are used to build cache keys and URL/output paths, which must use forward slashes on every OS. `ValidateBatchID` rejects any ID containing a backslash so Windows-style path fragments can't leak into keys and produce platform-dependent output. (Non-top-level IDs additionally reject forward slashes.)","triggerScenarios":"Passing an ID like `js.Batch \"js\\\\main\"` or a group/script ID built from a Windows file path (`.File.Path` on Windows yields backslashes) containing `\\`.","commonSituations":"Deriving IDs from filesystem paths on Windows; escaping mistakes in templates producing literal backslashes; copying paths from Windows Explorer into config.","solutions":["Use forward slashes (top-level IDs only) or plain segment names with no path separators.","If deriving from a file path, normalize first, e.g. `replace $path \"\\\\\" \"/\"` or use path.Base/filepath-agnostic helpers.","Prefer simple stable identifiers (\"main\", \"search\") over path-derived IDs."],"exampleFix":"{{/* before */}}\n{{ $batch := js.Batch \"js\\\\main\" }}\n{{/* after */}}\n{{ $batch := js.Batch \"js/main\" }}","handlingStrategy":"validation","validationCode":"if strings.ContainsRune(id, '\\\\') {\n    id = strings.ReplaceAll(id, \"\\\\\", \"/\")\n}","typeGuard":"func validBatchID(id string) bool {\n    return id != \"\" && !strings.ContainsRune(id, '\\\\')\n}","tryCatchPattern":null,"preventionTips":["Use forward slashes in batch ids everywhere, including on Windows — never feed filepath-derived strings (filepath.Join, os paths) directly as ids.","If an id comes from a file path, normalize with filepath.ToSlash or path helpers first.","Keep ids simple slugs (letters, digits, dashes, slashes) so they're portable across OSes and safe in URLs."],"tags":["hugo","js-batch","validation","windows","paths"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}