{"record":{"id":"09265092b8aab129","repo":"gravitational/teleport","slug":"error-writing-merged-json-w","errorCode":null,"errorMessage":"error writing merged JSON: %w","messagePattern":"error writing merged JSON: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/accessgraph/apiclient/jsonmerge/jsonmerge.go","lineNumber":50,"sourceCode":"\t\tdata = []byte(`{}`)\n\t}\n\tif patch == nil {\n\t\tpatch = []byte(`{}`)\n\t}\n\n\tvar dataValue any\n\tif err := unmarshalJSON(data, &dataValue); err != nil {\n\t\treturn nil, fmt.Errorf(\"error in data JSON: %w\", err)\n\t}\n\n\tvar patchValue any\n\tif err := unmarshalJSON(patch, &patchValue); err != nil {\n\t\treturn nil, fmt.Errorf(\"error in patch JSON: %w\", err)\n\t}\n\n\tmerged, err := json.Marshal(mergeJSON(dataValue, patchValue))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error writing merged JSON: %w\", err)\n\t}\n\treturn merged, nil\n}\n\nfunc unmarshalJSON(data []byte, value any) error {\n\tdecoder := json.NewDecoder(bytes.NewReader(data))\n\tdecoder.UseNumber()\n\treturn decoder.Decode(value)\n}\n\nfunc mergeJSON(data, patch any) any {\n\tpatchObject, ok := patch.(map[string]any)\n\tif !ok {\n\t\treturn data\n\t}\n\n\tswitch dataObject := data.(type) {\n\tcase map[string]any:","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/lib/accessgraph/apiclient/jsonmerge/jsonmerge.go#L32-L68","documentation":"After successfully merging the two decoded JSON values, JSONMerge re-serializes the result with json.Marshal and wraps any failure. Because the merged value is built from already-decoded JSON, this is rare — it mainly guards against internal invariants (e.g. unsupported values introduced by custom mergeJSON behavior such as NaN-like or channel-bearing values).","triggerScenarios":"json.Marshal of the mergeJSON(dataValue, patchValue) result fails — practically only if mergeJSON inserts a value json.Marshal cannot represent (channels, funcs, cyclic structures) rather than plain decoded JSON.","commonSituations":"A code change to mergeJSON that introduces non-marshalable sentinel values; custom unmarshalJSON hooks producing exotic types; otherwise this indicates a library bug rather than caller input.","solutions":["Inspect the wrapped marshal error message for the offending Go type/value.","Check recent changes to mergeJSON in lib/accessgraph/apiclient/jsonmerge for non-JSON-safe values.","Ensure both inputs are plain JSON documents (objects/arrays/scalars); report a bug if inputs are plainly valid."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Inputs can be validated; marshal failure is internal — ensure inputs are plain JSON:\nif !json.Valid(data) || !json.Valid(patch) { return nil, errors.New(\"inputs must be valid JSON\") }","typeGuard":null,"tryCatchPattern":"merged, err := jsonmerge.JSONMerge(data, patch)\nif err != nil {\n\tif strings.Contains(err.Error(), \"error writing merged JSON\") {\n\t\t// likely a jsonmerge internals bug: log inputs and file an issue\n\t}\n}","preventionTips":["Only pass documents that came from json.Marshal or decoding of real JSON.","Keep mergeJSON free of non-JSON-serializable sentinel values.","Add a regression test that merges representative data/patch pairs and re-marshals the output."],"tags":["json","accessgraph","marshal","merge"],"backgroundTag":"json-marshal-failed","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}