gohugoio/hugo · error
npm pack: failed to marshal package.json with updated worksp
Error message
npm pack: failed to marshal package.json with updated workspaces: %w
What it means
After appending Hugo's autogenerated workspace path to the object-form `workspaces.packages` array, Hugo re-serializes the whole package.json with json.MarshalIndent. This error wraps a marshal failure at that step. Since the input was just unmarshalled from JSON, marshal failures here are essentially never seen in practice — it's a defensive wrap around the encoder.
Source
Thrown at modules/npm/package_builder.go:292
packagesSlice := toStringSlice(packagesVal)
if slices.Contains(packagesSlice, workspacePath) {
if runtime.GOOS == "windows" {
return afero.WriteFile(fsys, packageJSONName, data, 0o666)
}
return nil
}
// Append the new workspace path to the packages slice.
newPkgs := make([]any, 0, len(packagesSlice)+1)
for _, s := range packagesSlice {
newPkgs = append(newPkgs, s)
}
newPkgs = append(newPkgs, workspacePath)
v["packages"] = newPkgs
updated, err := json.MarshalIndent(pkg, "", indent)
if err != nil {
return fmt.Errorf("npm pack: failed to marshal package.json with updated workspaces: %w", err)
}
updated = append(updated, '\n')
return afero.WriteFile(fsys, packageJSONName, updated, 0o666)
case nil:
// Treat explicit null as "no workspaces"; handled below as missing key.
default:
return fmt.Errorf("npm pack: unsupported workspaces type %T", v)
}
// Try adding to existing workspaces array when present.
if hasWS && wsVal != nil {
if wsIdx := bytes.Index(data, []byte(`"workspaces"`)); wsIdx >= 0 {
rest := data[wsIdx:]
if bracketOpen := bytes.IndexByte(rest, '['); bracketOpen >= 0 {
if bracketClose := bytes.IndexByte(rest[bracketOpen:], ']'); bracketClose >= 0 {
pos := wsIdx + bracketOpen + bracketClose
arrayContent := bytes.TrimSpace(data[wsIdx+bracketOpen+1 : pos])
var insertion stringView on GitHub ↗ (pinned to 8a468df065)
Solutions
- Re-run the command; if it reproduces, note this indicates an internal inconsistency.
- Convert `workspaces` to the simpler array form to bypass the object-form re-marshal path entirely.
- Report the reproducer to the Hugo issue tracker with your package.json and Hugo version.
Defensive patterns
Strategy: try-catch
Validate before calling
// ensure workspaces contains only JSON-serializable values (strings)
for _, w := range workspaces {
if _, ok := w.(string); !ok {
return fmt.Errorf("workspace entry %v is not a string", w)
}
} Try / catch
if err := b.Build(); err != nil {
if strings.Contains(err.Error(), "failed to marshal package.json") {
log.Fatal("package.json contains values that cannot be re-serialized; simplify workspaces to a string array")
}
return err
} Prevention
- Keep workspaces entries as plain strings/globs
- Avoid exotic nested structures in package.json that round-trip poorly through generic JSON handling
When it happens
Trigger: `hugo mod npm pack` taking the object-form workspaces path (map with `packages`), followed by json.MarshalIndent failing — which for data round-tripped through json.Unmarshal (only strings, numbers, bools, maps, slices) does not normally occur.
Common situations: Practically unheard of in normal use; would require the in-memory package map to contain unmarshalable values, pointing at a Hugo bug or memory corruption rather than user config.
Related errors
- conf must be set
- npm pack: failed to parse package.json: %w
- npm pack: failed to open package file: %w
- npm pack: failed to build: %w
- npm pack: unsupported workspaces object; missing "packages"
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/80d1ab268d4291aa.json.
Report an issue: GitHub ↗.