{"record":{"id":"553658021d055bb6","repo":"gohugoio/hugo","slug":"npm-pack-unsupported-workspaces-object-missing","errorCode":null,"errorMessage":"npm pack: unsupported workspaces object; missing \"packages\" field","messagePattern":"npm pack: unsupported workspaces object; missing \"packages\" field","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/npm/package_builder.go","lineNumber":272,"sourceCode":"\tquoted := fmt.Sprintf(\"%q\", workspacePath)\n\n\twsVal, hasWS := pkg[\"workspaces\"]\n\n\tswitch v := wsVal.(type) {\n\tcase []any:\n\t\t// Array form: [\"pkg-a\", \"pkg-b\", ...]\n\t\tif slices.Contains(toStringSlice(v), workspacePath) {\n\t\t\tif runtime.GOOS == \"windows\" {\n\t\t\t\treturn afero.WriteFile(fsys, packageJSONName, data, 0o666)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\t// Fall through to byte-based insertion into the existing array below.\n\tcase map[string]any:\n\t\t// Object form: { \"workspaces\": { \"packages\": [...] } }\n\t\tpackagesVal, ok := v[\"packages\"]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"npm pack: unsupported workspaces object; missing \\\"packages\\\" field\")\n\t\t}\n\t\tpackagesSlice := toStringSlice(packagesVal)\n\t\tif slices.Contains(packagesSlice, workspacePath) {\n\t\t\tif runtime.GOOS == \"windows\" {\n\t\t\t\treturn afero.WriteFile(fsys, packageJSONName, data, 0o666)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\t// Append the new workspace path to the packages slice.\n\t\tnewPkgs := make([]any, 0, len(packagesSlice)+1)\n\t\tfor _, s := range packagesSlice {\n\t\t\tnewPkgs = append(newPkgs, s)\n\t\t}\n\t\tnewPkgs = append(newPkgs, workspacePath)\n\t\tv[\"packages\"] = newPkgs\n\n\t\tupdated, err := json.MarshalIndent(pkg, \"\", indent)","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/modules/npm/package_builder.go#L254-L290","documentation":"In ensureWorkspaceRef (modules/npm/package_builder.go:272). When the root package.json uses the object form of 'workspaces' (\"workspaces\": { ... }), Hugo requires a \"packages\" field inside it (the npm/yarn convention). If the object lacks \"packages\", the structure is unsupported and the error is returned without a wrapped cause.","triggerScenarios":"package.json contains \"workspaces\": { \"nope\": [...] } or an object form of workspaces without a packages key. This can happen with exotic monorepo tooling or hand-edited configs.","commonSituations":"Switching a project to/from pnpm-style workspaces without the packages key; a tool that writes a workspaces object with a different key; manually restructuring workspaces.","solutions":["Restructure the workspaces field to the standard object form: \"workspaces\": { \"packages\": [\"pkg-a\", \"pkg-b\"] }.","Or use the simpler array form: \"workspaces\": [\"pkg-a\", \"pkg-b\"], which Hugo also supports.","Ensure no extraneous keys replaced 'packages'."],"exampleFix":"// before\n\"workspaces\": { \"apps\": [\"apps/*\"] }\n\n// after\n\"workspaces\": { \"packages\": [\"apps/*\"] }\n// or simply\n\"workspaces\": [\"apps/*\"]","handlingStrategy":"type-guard","validationCode":"// ensure workspaces object form has packages\ndata, _ := os.ReadFile(\"package.json\")\nvar pkg map[string]any\n_ = json.Unmarshal(data, &pkg)\nif ws, ok := pkg[\"workspaces\"].(map[string]any); ok {\n    if _, hasPkgs := ws[\"packages\"]; !hasPkgs {\n        return errors.New(`workspaces object must contain \"packages\"`)\n    }\n}","typeGuard":"func isSupportedWorkspacesArrayForm(v any) bool {\n    switch v.(type) {\n    case []any, map[string]any, nil:\n        return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Use the array workspaces form for simplicity.","If using object form, always include packages.","Validate package.json structure in CI."],"tags":["hugo","npm-pack","workspaces"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}