gohugoio/hugo · error
npm pack: malformed package.json
Error message
npm pack: malformed package.json
What it means
When the root package.json has no `workspaces` key at all, Hugo appends one by inserting text before the file's final closing brace. If the raw bytes contain no `}` at all, the file can't be a JSON object and Hugo bails out. Note the earlier json.Unmarshal succeeded, so this state means the parsed value wasn't a normal object body — an edge case guard against writing garbage.
Source
Thrown at modules/npm/package_builder.go:332
insertion = ",\n" + indent + indent + quoted + "\n" + indent
}
result := make([]byte, 0, len(data)+len(insertion))
result = append(result, data[:pos]...)
result = append(result, insertion...)
result = append(result, data[pos:]...)
return afero.WriteFile(fsys, packageJSONName, result, 0o666)
}
}
}
// We know a workspaces array exists but could not locate it reliably in the raw data.
return fmt.Errorf("npm pack: could not locate existing workspaces array for insertion")
}
// No workspaces key — add before closing brace.
lastBrace := bytes.LastIndexByte(data, '}')
if lastBrace < 0 {
return fmt.Errorf("npm pack: malformed package.json")
}
before := bytes.TrimRight(data[:lastBrace], " \t\n\r")
needComma := len(before) > 0 && before[len(before)-1] != '{' && before[len(before)-1] != ','
var insertion string
if needComma {
insertion = ",\n" + indent + `"workspaces": [` + "\n" + indent + indent + quoted + "\n" + indent + "]\n"
} else {
insertion = indent + `"workspaces": [` + "\n" + indent + indent + quoted + "\n" + indent + "]\n"
}
result := make([]byte, 0, len(data)+len(insertion))
result = append(result, before...)
result = append(result, insertion...)
result = append(result, data[lastBrace:]...)
return afero.WriteFile(fsys, packageJSONName, result, 0o666)
}View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Inspect package.json and restore it to a valid JSON object (`{ ... }`) — regenerate with `npm init -y` if needed.
- Check for truncation from interrupted writes or disk-full conditions, restore from git (`git checkout -- package.json`).
- Re-run `hugo mod npm pack` after the file is a well-formed object.
Defensive patterns
Strategy: validation
Validate before calling
var v map[string]any
if err := json.Unmarshal(mustRead("package.json"), &v); err != nil {
return fmt.Errorf("package.json malformed: %w", err)
}
// also ensure top level is an object, not an array/scalar Type guard
func isJSONObjectFile(data []byte) bool {
var v map[string]any
return json.Unmarshal(data, &v) == nil
} Try / catch
if err := b.Build(); err != nil {
if strings.Contains(err.Error(), "malformed package.json") {
log.Fatal("package.json must be a JSON object; run `npm pkg fix` or recreate with `npm init -y`")
}
return err
} Prevention
- Top level of package.json must be a JSON object `{...}`, not an array or scalar
- Regenerate a broken file with `npm init -y` and re-add fields via `npm pkg set`
- Add a JSON validity check for package.json to pre-commit/CI
When it happens
Trigger: `hugo mod npm pack` on a package.json whose bytes contain no closing brace — practically only possible if the file parses as something odd (this path requires unmarshal into map to have succeeded, so it is a defensive guard; near-zero-byte or corrupted files hit the parse error first).
Common situations: Truncated or corrupted package.json produced by an interrupted write; extremely unusual encodings. Most real-world corruption is caught earlier by the parse-error path (index 122); this guard covers the residual gap.
Related errors
- npm pack: failed to parse package.json: %w
- npm pack: failed to build: %w
- npm pack: unsupported workspaces object; missing "packages"
- npm pack: unsupported workspaces type %T
- npm pack: failed to open package file: %w
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/13bd7ec608a1266b.json.
Report an issue: GitHub ↗.