gohugoio/hugo · error
npm pack: malformed package.json
Error message
npm pack: malformed package.json
What it means
In ensureWorkspaceRef (modules/npm/package_builder.go:332). When there is no existing workspaces key, Hugo inserts one before the last '}' of package.json. bytes.LastIndexByte(data, '}') returns -1 when no closing brace is present, so the file is declared malformed. Although the earlier json.Unmarshal would normally catch bad JSON, this guards the byte-edit step.
Solutions
- Restore package.json from version control or regenerate it.
- Validate it parses as JSON and ends with '}'.
- Prevent concurrent writers from touching package.json during 'hugo'.
Example fix
// before: truncated package.json
{ "name": "proj", "dependencies": { "x": "^1.0"
// after
{
"name": "proj",
"dependencies": { "x": "^1.0" }
} Defensive patterns
Strategy: validation
Validate before calling
data, err := os.ReadFile("package.json")
if err != nil {
return err
}
if bytes.LastIndexByte(data, '}') < 0 {
return errors.New("package.json is malformed: missing closing brace")
}
var v any
return json.Unmarshal(data, &v) Prevention
- Restore package.json from VCS if truncated.
- Prevent concurrent writers during builds.
- Validate package.json integrity in CI.
When it happens
Trigger: package.json has no closing '}' — truncated, or assembled from fragments. This typically implies the file became corrupt after the earlier unmarshal or the read/parse/write path is inconsistent.
Common situations: A truncated package.json written by a crashed process; a file stripped of its closing brace by a bad sed/regex edit; concurrent writes during the build.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- npm pack: failed to build
- npm pack: failed to marshal package.json with updated…
- npm pack: failed to parse package.json
- npm pack: failed to parse
- failed to decode file cache entry
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/13bd7ec608a1266b.
Report an issue: GitHub.
Appendix: 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 52c9bd7908)