gohugoio/hugo · error

id must not contain backslashes

Error message

id must not contain backslashes

What it means

ValidateBatchID forbids backslashes in a batch id (batch.go:157-158) because backslashes conflict with path handling and virtual import resolution on Windows and produce ambiguous keys. Any id containing '\' is rejected.

Solutions

  1. Build ids with forward slashes only (use path.Join, not filepath.Join, for virtual ids).
  2. Sanitize existing strings: replace '\' with '/' before use.
  3. Prefer Hugo's paths helpers which normalize separators.

Example fix

// before (Windows)
id := filepath.Join("assets", "main") // "assets\main"

// after
id := path.Join("assets", "main") // "assets/main"
Defensive patterns

Strategy: validation

Validate before calling

func sanitizeBatchID(id string) (string, error) {
    if strings.Contains(id, "\\") {
        return "", fmt.Errorf("id must not contain backslashes")
    }
    return id, nil
}

// Or normalize: strings.ReplaceAll(id, "\\", "/")

Type guard

func hasNoBackslashes(id string) bool { return !strings.Contains(id, "\\") }

Prevention

When it happens

Trigger: Passing a Windows-style path (e.g. "assets\\scripts\\main") as a batch id; a string built with backslash separators instead of forward slashes.

Common situations: Code running on Windows that joins paths with filepath.Join (backslash separator) and passes the result as a batch id; copy-pasting a Windows path literal.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/da5518274d8d085e. Report an issue: GitHub.

Appendix: source

Thrown at internal/js/esbuild/batch.go:158

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),
	}
}

func newOpts[K any, C optionsCompiler[C]](key K, optionsID string, defaults defaultOptionValues) *opts[K, C] {

View on GitHub (pinned to 52c9bd7908)