{"id":"13bd7ec608a1266b","repo":"gohugoio/hugo","slug":"npm-pack-malformed-package-json","errorCode":null,"errorMessage":"npm pack: malformed package.json","messagePattern":"npm pack: malformed package\\.json","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/npm/package_builder.go","lineNumber":332,"sourceCode":"\t\t\t\t\t\tinsertion = \",\\n\" + indent + indent + quoted + \"\\n\" + indent\n\t\t\t\t\t}\n\t\t\t\t\tresult := make([]byte, 0, len(data)+len(insertion))\n\t\t\t\t\tresult = append(result, data[:pos]...)\n\t\t\t\t\tresult = append(result, insertion...)\n\t\t\t\t\tresult = append(result, data[pos:]...)\n\t\t\t\t\treturn afero.WriteFile(fsys, packageJSONName, result, 0o666)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// We know a workspaces array exists but could not locate it reliably in the raw data.\n\t\treturn fmt.Errorf(\"npm pack: could not locate existing workspaces array for insertion\")\n\t}\n\n\t// No workspaces key — add before closing brace.\n\tlastBrace := bytes.LastIndexByte(data, '}')\n\tif lastBrace < 0 {\n\t\treturn fmt.Errorf(\"npm pack: malformed package.json\")\n\t}\n\n\tbefore := bytes.TrimRight(data[:lastBrace], \" \\t\\n\\r\")\n\tneedComma := len(before) > 0 && before[len(before)-1] != '{' && before[len(before)-1] != ','\n\n\tvar insertion string\n\tif needComma {\n\t\tinsertion = \",\\n\" + indent + `\"workspaces\": [` + \"\\n\" + indent + indent + quoted + \"\\n\" + indent + \"]\\n\"\n\t} else {\n\t\tinsertion = indent + `\"workspaces\": [` + \"\\n\" + indent + indent + quoted + \"\\n\" + indent + \"]\\n\"\n\t}\n\n\tresult := make([]byte, 0, len(data)+len(insertion))\n\tresult = append(result, before...)\n\tresult = append(result, insertion...)\n\tresult = append(result, data[lastBrace:]...)\n\treturn afero.WriteFile(fsys, packageJSONName, result, 0o666)\n}","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/modules/npm/package_builder.go#L314-L350","documentation":"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.","triggerScenarios":"`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).","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"var v map[string]any\nif err := json.Unmarshal(mustRead(\"package.json\"), &v); err != nil {\n    return fmt.Errorf(\"package.json malformed: %w\", err)\n}\n// also ensure top level is an object, not an array/scalar","typeGuard":"func isJSONObjectFile(data []byte) bool {\n    var v map[string]any\n    return json.Unmarshal(data, &v) == nil\n}","tryCatchPattern":"if err := b.Build(); err != nil {\n    if strings.Contains(err.Error(), \"malformed package.json\") {\n        log.Fatal(\"package.json must be a JSON object; run `npm pkg fix` or recreate with `npm init -y`\")\n    }\n    return err\n}","preventionTips":["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"],"tags":["hugo","npm-pack","package-json","corruption"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}