{"record":{"id":"af9ca3678dff6dda","repo":"gohugoio/hugo","slug":"npm-pack-failed-to-marshal-json-w","errorCode":null,"errorMessage":"npm pack: failed to marshal JSON: %w","messagePattern":"npm pack: failed to marshal JSON: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/npm/package_builder.go","lineNumber":368,"sourceCode":"}\n\nfunc detectIndent(data []byte) string {\n\tfor line := range bytes.SplitSeq(data, []byte(\"\\n\")) {\n\t\ttrimmed := bytes.TrimLeft(line, \" \\t\")\n\t\tif len(trimmed) < len(line) && len(trimmed) > 0 && trimmed[0] == '\"' {\n\t\t\treturn string(line[:len(line)-len(trimmed)])\n\t\t}\n\t}\n\treturn \"  \"\n}\n\nfunc writeJSON(fs afero.Fs, filename string, v any) error {\n\tbuf := new(bytes.Buffer)\n\tencoder := json.NewEncoder(buf)\n\tencoder.SetEscapeHTML(false)\n\tencoder.SetIndent(\"\", strings.Repeat(\" \", 2))\n\tif err := encoder.Encode(v); err != nil {\n\t\treturn fmt.Errorf(\"npm pack: failed to marshal JSON: %w\", err)\n\t}\n\treturn afero.WriteFile(fs, filename, buf.Bytes(), 0o666)\n}\n\nfunc toStringSlice(v any) []string {\n\tif v == nil {\n\t\treturn nil\n\t}\n\tif s, ok := v.([]any); ok {\n\t\tvar out []string\n\t\tfor _, item := range s {\n\t\t\tif str, ok := item.(string); ok {\n\t\t\t\tout = append(out, str)\n\t\t\t}\n\t\t}\n\t\treturn out\n\t}\n\treturn nil","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/modules/npm/package_builder.go#L350-L386","documentation":"Thrown by the writeJSON helper inside Hugo's npm package builder (modules/npm/package_builder.go:368) when encoding/json.Encoder.Encode returns an error while serializing the auto-generated package.json or package metadata. The %w wraps the underlying json error, which Go produces when the value contains a type that cannot be marshaled (chan, func, complex) or a self-referential structure. In Hugo this value is constructed internally from module dependency maps, so it typically indicates corrupt or unexpectedly-typed module dependency data rather than user-authored JSON.","triggerScenarios":"Hugo invokes writeJSON with the autoGenPkg map (name, version, dependencies, devDependencies) at line 214 and the packageMeta struct at line 231. The error fires only if Encoder.Encode(v) returns non-nil — i.e., one of the dependency values inside moduleDeps/moduleDevDeps cannot be JSON-serialized (e.g. a func, chan, or a map with a non-string key) or a struct field is unexported/incompatible.","commonSituations":"A Hugo module declares a dependency whose resolved metadata contains an unsupported Go type (rare, usually a Hugo internal bug); a third-party module patches the dependency map with a non-serializable value; upgrading Hugo changes the module dependency structure; the workspace package auto-generation (_hugoautogen) hits inconsistent state after a failed prior build leaving stale artifacts.","solutions":["Clear the Hugo build cache and the _hugoautogen workspace directory, then rebuild: rm -rf _hugoautogen and run hugo --gc.","Inspect the module declarations in hugo.toml/hugo.yaml for malformed dependencies and remove or fix any non-string values in the replacements/mounts/imports.","Check the error chain (%w) printed by Hugo to identify which field/type failed to marshal, then report a Hugo issue if the value originates from Hugo internals rather than your config.","Pin to a known-good Hugo version if the regression appeared after an upgrade."],"exampleFix":"// before (malformed module dep with non-string value)\n[module]\n  [[module.imports]]\n    path = \"github.com/x/y\"\n    ignoreConfig = [\"a\"]   // array where scalar expected by resolver\n\n// after\n[module]\n  [[module.imports]]\n    path = \"github.com/x/y\"\n    ignoreConfig = \"a\"","handlingStrategy":"try-catch","validationCode":"// Validate module dependency maps contain only JSON-serializable values before build.\nfunc depsAreJSONSerializable(m map[string]any) error {\n    for k, v := range m {\n        if err := json.Marshal(v); err != nil {\n            return fmt.Errorf(\"dependency %q not serializable: %w\", k, err)\n        }\n    }\n    return nil\n}","typeGuard":"// Reject chan/func/complex which json.Encoder cannot marshal.\nfunc isJSONSerializable(v any) bool {\n    rv := reflect.ValueOf(v)\n    switch rv.Kind() {\n    case reflect.Chan, reflect.Func, reflect.Complex64, reflect.Complex128:\n        return false\n    }\n    return true\n}","tryCatchPattern":"err := writeJSON(fs, file, pkg)\nif err != nil {\n    // Surface the wrapped json error, clean _hugoautogen, and abort the npm pack step.\n    log.Printf(\"npm pack json marshal failed: %v\", err)\n    return fmt.Errorf(\"cannot write %s: %w\", file, err)\n}","preventionTips":["Keep module dependency declarations as plain string versions/paths.","Clear _hugoautogen between builds when iterating on module config.","Pin Hugo versions in CI to detect regressions in dependency resolution."],"tags":["npm","json","modules","serialization","hugo"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}