gohugoio/hugo · error
npm pack: unsupported workspaces type %T
Error message
npm pack: unsupported workspaces type %T
What it means
In ensureWorkspaceRef (modules/npm/package_builder.go:299). The workspaces field is type-switched; array ([]any), object (map[string]any) and nil are handled. Any other concrete type (e.g. a string or number) hits the default branch and returns 'unsupported workspaces type %T', printing the Go type.
Solutions
- Change workspaces to an array: "workspaces": ["apps/*"].
- Or use the object form: "workspaces": { "packages": ["apps/*"] }.
- Validate package.json shape against the npm spec.
Example fix
// before "workspaces": "apps/*" // after "workspaces": ["apps/*"]
Defensive patterns
Strategy: type-guard
Validate before calling
var pkg map[string]any
_ = json.Unmarshal(data, &pkg)
switch pkg["workspaces"].(type) {
case []any, map[string]any, nil:
// ok
default:
return fmt.Errorf("workspaces must be array or object, got %T", pkg["workspaces"])
} Type guard
func isSupportedWorkspaces(v any) bool {
switch v.(type) {
case []any, map[string]any, nil:
return true
}
return false
} Prevention
- Always make workspaces an array (even single-element).
- Validate package.json with a JSON schema in CI.
- Avoid string-shortcut forms for workspaces.
When it happens
Trigger: package.json has "workspaces": "apps/*" (a string) or "workspaces": 3 (a number). npm expects workspaces to be an array or an object with packages, so a scalar value is rejected.
Common situations: Typing workspaces as a single glob string instead of a one-element array; a config generator emitting the wrong shape; confusion with tools that accept string shortcuts.
Related errors
- npm pack: could not locate existing workspaces array for…
- npm pack: failed to marshal package.json with updated…
- npm pack: unsupported workspaces object; missing "packages"…
- argument must be a slice
- called apply using as type
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/838649995811c264.
Report an issue: GitHub.
Appendix: source
Thrown at modules/npm/package_builder.go:299
// 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 string
if len(arrayContent) == 0 {
insertion = "\n" + indent + indent + quoted + "\n" + indent
} else {
insertion = ",\n" + indent + indent + quoted + "\n" + indent
}
result := make([]byte, 0, len(data)+len(insertion))
result = append(result, data[:pos]...)View on GitHub (pinned to 52c9bd7908)