gohugoio/hugo · error

npm pack: failed to marshal package.json with updated…

Error message

npm pack: failed to marshal package.json with updated workspaces: %w

What it means

In ensureWorkspaceRef (modules/npm/package_builder.go:292). After appending the workspace path to the packages array of the workspaces object form, Hugo re-marshals the whole package.json with json.MarshalIndent using the detected indent. Failure is wrapped. json.MarshalIndent on a map[string]any parsed from valid JSON essentially never fails, so this is a defensive guard.

Solutions

  1. Inspect package.json for unusual value types (numbers, booleans, nested objects) and normalize them to standard package.json content.
  2. Recreate package.json from a known-good source.
  3. Report to Hugo if the file is valid JSON yet this still fires.

Example fix

// before: package.json contains an unmarshallable value
"workspaces": { "packages": [12345] }

// after
"workspaces": { "packages": ["pkg-a"] }
Defensive patterns

Strategy: validation

Validate before calling

var pkg map[string]any
if err := json.Unmarshal(data, &pkg); err != nil {
    return err
}
// reject values json.Marshal cannot round-trip (NaN etc.)
if _, err := json.Marshal(pkg); err != nil {
    return fmt.Errorf("package.json contains unmarshallable values: %w", err)
}

Prevention

When it happens

Trigger: The reassembled package object contains a value type json.Marshal cannot encode (e.g. a NaN float, a channel, or a circular structure introduced by an exotic field). Practically unreachable from normal package.json content.

Common situations: Corrupted in-memory representation after manual mutation; extremely unusual non-string value types in package.json that survived the earlier unmarshal as unsupported types.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/80d1ab268d4291aa. Report an issue: GitHub.

Appendix: source

Thrown at modules/npm/package_builder.go:292

		packagesSlice := toStringSlice(packagesVal)
		if slices.Contains(packagesSlice, workspacePath) {
			if runtime.GOOS == "windows" {
				return afero.WriteFile(fsys, packageJSONName, data, 0o666)
			}
			return nil
		}

		// 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

View on GitHub (pinned to 52c9bd7908)