gohugoio/hugo · error
id must be set
Error message
id must be set
What it means
ValidateBatchID rejects an empty batch identifier (batch.go:152-154). A JS bundle batch requires a non-empty id used as a cache key and import path component; an empty id would collide and produce ambiguous virtual paths. The error is returned from ValidateBatchID and also surfaces via panic when called through BatchGroup (line 353-355).
Solutions
- Provide a non-empty, slash/backslash-free id when creating or grouping batches.
- Assert the id is non-empty before calling the batch API (guard at the call site).
- Trace where the empty id originates (likely an unset option or empty keyPath).
Example fix
// before
group := batcher.Group(ctx, "")
// after
if id == "" { return fmt.Errorf("batch id required") }
group := batcher.Group(ctx, id) Defensive patterns
Strategy: validation
Validate before calling
func requireBatchID(id string) error {
if id == "" {
return fmt.Errorf("id must be set")
}
return nil
} Type guard
func isNonEmptyID(id string) bool { return id != "" } Prevention
- Always derive batch ids from non-empty, validated sources.
- Guard the call site with an empty-string check to avoid Group's panic.
- Unit-test batch construction with empty input to confirm the guard.
When it happens
Trigger: Calling js/esbuild batch APIs (Batcher.Group or similar) with an empty string id, or constructing a batcher whose id field was never set. Group calls ValidateBatchID(id,false) and panics on error.
Common situations: Programmatic batch construction where the id is derived from an unset variable; a refactor that dropped the id assignment; a template path resolving to empty.
Related errors
- id must not contain forward slashes
- failed to build JS batch
- failed to build JS batch
- id must not contain backslashes
- only esm format is currently supported
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/ccf800ff35c83e13.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/esbuild/batch.go:154
func (o *opts[K, C]) GetIdentity() identity.Identity {
return o.h
}
func (o *optsHolder[C]) SetOptions(m map[string]any) string {
o.optsSetCounter++
o.optsPrev = o.optsCurr
o.optsCurr = m
o.compiledPrev = o.compiled
o.compiled, o.compileErr = o.compiled.compileOptions(m, o.defaults)
o.checkCompileErr()
return ""
}
// ValidateBatchID validates the given ID according to some very
func ValidateBatchID(id string, isTopLevel bool) error {
if id == "" {
return fmt.Errorf("id must be set")
}
// No Windows slashes.
if strings.Contains(id, "\\") {
return fmt.Errorf("id must not contain backslashes")
}
// Allow forward slashes in top level IDs only.
if !isTopLevel && strings.Contains(id, "/") {
return fmt.Errorf("id must not contain forward slashes")
}
return nil
}
func newIsBuiltOrTouched() isBuiltOrTouched {
return isBuiltOrTouched{
built: make(buildIDs),
touched: make(buildIDs),View on GitHub (pinned to 52c9bd7908)