{"id":"ccf800ff35c83e13","repo":"gohugoio/hugo","slug":"id-must-be-set","errorCode":null,"errorMessage":"id must be set","messagePattern":"id must be set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/esbuild/batch.go","lineNumber":154,"sourceCode":"\nfunc (o *opts[K, C]) GetIdentity() identity.Identity {\n\treturn o.h\n}\n\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),","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/internal/js/esbuild/batch.go#L136-L172","documentation":"`ValidateBatchID` guards every ID used in the js.Batch API (batch names, group names, script/instance/runner IDs) because these IDs become cache keys and output paths. An empty string is rejected outright with this error.","triggerScenarios":"Calling `js.Batch \"\"`, `.Group \"\"`, or adding a script/instance/runner with an empty ID — e.g. `{{ $batch := js.Batch \"\" }}` or an ID templated from a variable/param that evaluates to empty.","commonSituations":"Deriving the ID from a page param or `.File.BaseFileName` that is unset for some pages; refactoring that drops a hardcoded ID; passing the wrong variable to the batch call.","solutions":["Pass a non-empty ID string to js.Batch/Group/WithScript etc.","If the ID is computed, guard it: `{{ with $id }}{{ $batch := js.Batch . }}...{{ end }}` or fail loudly with errorf.","Check the page/site param the ID is derived from is set for every page that renders the template."],"exampleFix":"{{/* before */}}\n{{ $batch := js.Batch $.Param \"batchid\" }}\n{{/* after */}}\n{{ $id := $.Param \"batchid\" | default \"main\" }}\n{{ $batch := js.Batch $id }}","handlingStrategy":"validation","validationCode":"// Before registering a batch script/instance/runner:\nif id == \"\" {\n    return errors.New(\"js.Batch script id must be a non-empty string\")\n}","typeGuard":"func validBatchID(id string) bool {\n    return id != \"\" && !strings.ContainsRune(id, '\\\\')\n}","tryCatchPattern":null,"preventionTips":["Always pass an explicit, stable id as the first argument to Group/Script/Instance calls in js.Batch templates.","Derive ids from known values (page path, script name), and verify the deriving expression can't produce empty for any page.","Guard templated ids: {{ if not $id }}{{ errorf \"missing batch id\" }}{{ end }}."],"tags":["hugo","js-batch","validation","template-options"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}