{"record":{"id":"6aafdb52ef96adc7","repo":"gastownhall/beads","slug":"failed-to-marshal-metadata-w-6aafdb","errorCode":null,"errorMessage":"failed to marshal metadata: %w","messagePattern":"failed to marshal metadata: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/metadata.go","lineNumber":310,"sourceCode":"\t\tif !ok || k == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"invalid --set-metadata: expected key=value, got %q\", kv)\n\t\t}\n\t\tif err := ValidateMetadataKey(k); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdata[k] = MetadataEditValue(v)\n\t}\n\n\tfor _, k := range unsetFlags {\n\t\tif err := ValidateMetadataKey(k); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdelete(data, k)\n\t}\n\n\tresult, err := json.Marshal(data)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to marshal metadata: %w\", err)\n\t}\n\treturn json.RawMessage(result), nil\n}\n\n// MetadataEditValue converts a --set-metadata string value to JSON. Per the CLI\n// contract (GH#4146), --set-metadata values are ALWAYS stored as JSON strings;\n// inferring numbers/booleans/null from string content silently broke\n// map[string]string round-trips for Go consumers (a numeric-looking id or a\n// version like \"1e3\" came back as a JSON number). Typed values go through the\n// explicit --metadata / --metadata-json path (MergeMetadataJSON).\nfunc MetadataEditValue(s string) json.RawMessage {\n\tb, _ := json.Marshal(s)\n\treturn json.RawMessage(b)\n}\n","sourceCodeStart":292,"sourceCodeEnd":325,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/metadata.go#L292-L325","documentation":"After applying set/unset edits, ApplyMetadataEdits marshals the resulting map back to JSON and wraps any json.Marshal error. Since every stored value is produced via MetadataEditValue (which marshals a string) or came from successfully-decoded existing JSON, this error is very rare and acts as a defensive guard against writing corrupt metadata.","triggerScenarios":"A json.RawMessage in the working map is not valid JSON — possible if the existing metadata map was decoded from fragments that are individually invalid, or if the map was constructed by hand and passed through other code paths; essentially never fires on CLI-supplied flags.","commonSituations":"Programmatic callers composing json.RawMessage values manually with malformed content; corrupted stored metadata that happened to pass the initial Unmarshal through a loose path; encoder edge cases with pathological data.","solutions":["Ensure any raw values you inject are valid JSON (use json.Marshal to build them).","Reload the existing metadata from the database instead of reusing a hand-modified map.","If CLI-only, this indicates corrupt stored metadata — reset metadata to null and re-apply edits.","Report upstream with the offending metadata blob if reproducible from library output alone."],"exampleFix":"// before\ndata[\"x\"] = json.RawMessage(`{\"oops\"`) // invalid\nout, err := ApplyMetadataEdits(existing, nil, nil)\n// after\nraw, _ := json.Marshal(\"value\")\ndata[\"x\"] = raw\nout, err := ApplyMetadataEdits(existing, nil, nil)","handlingStrategy":"try-catch","validationCode":"func allValid(data map[string]json.RawMessage) bool {\n    for _, v := range data {\n        if !json.Valid(v) { return false }\n    }\n    return true\n} // check the working map before/during custom edit pipelines","typeGuard":"func validRaw(v json.RawMessage) bool { return json.Valid(v) }","tryCatchPattern":"out, err := ApplyMetadataEdits(existing, set, unset)\nif err != nil && strings.Contains(err.Error(), \"failed to marshal metadata\") {\n    // corrupt base: rebuild metadata from the set flags alone\n    out, err = ApplyMetadataEdits(nil, set, unset)\n}","preventionTips":["Construct metadata values only via json.Marshal or MetadataEditValue.","Treat marshal failures here as evidence of corrupt stored metadata and reload it.","Unit-test any code path that injects raw fragments into metadata maps."],"tags":["json","metadata","serialization"],"backgroundTag":"metadata-serialization-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}