{"record":{"id":"17ba40584dc45f1a","repo":"gastownhall/beads","slug":"existing-metadata-is-not-a-json-object-w","errorCode":null,"errorMessage":"existing metadata is not a JSON object: %w","messagePattern":"existing metadata is not a JSON object: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/update.go","lineNumber":931,"sourceCode":"\t\t}\n\t\tcurrent = merged\n\t}\n\t// Validate the merged result, matching the schema check stores apply to\n\t// direct metadata replacements (GH#1416 Phase 2).\n\tif err := ValidateMetadataIfConfigured(current); err != nil {\n\t\treturn err\n\t}\n\tresolved[\"metadata\"] = current\n\treturn nil\n}\n\nfunc applyTypedMetadataEdits(existing json.RawMessage, set map[string]json.RawMessage, unset []string) (json.RawMessage, error) {\n\tdata := make(map[string]json.RawMessage)\n\tif len(existing) > 0 {\n\t\ttrimmed := strings.TrimSpace(string(existing))\n\t\tif trimmed != \"\" && trimmed != \"null\" {\n\t\t\tif err := json.Unmarshal(existing, &data); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"existing metadata is not a JSON object: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\tkeys := make([]string, 0, len(set))\n\tfor key := range set {\n\t\tkeys = append(keys, key)\n\t}\n\tsort.Strings(keys)\n\tfor _, key := range keys {\n\t\tif err := storage.ValidateMetadataKey(key); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif !json.Valid(set[key]) {\n\t\t\treturn nil, fmt.Errorf(\"metadata value for key %q is not valid JSON\", key)\n\t\t}\n\t\tdata[key] = set[key]\n\t}\n\tfor _, key := range unset {","sourceCodeStart":913,"sourceCodeEnd":949,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/update.go#L913-L949","documentation":"During typed metadata edits, the issue's existing metadata could not be unmarshaled into a JSON object (map[string]json.RawMessage). The stored value exists but is not an object — e.g. an array, string, or number — so incremental edits cannot be applied to it.","triggerScenarios":"applyTypedMetadataEdits is called (via resolveMetadataMergeOps -> set/unset metadata ops) while the issue's stored metadata column holds a non-object JSON document.","commonSituations":"Legacy data written before object-only metadata was enforced, imports from external tools storing arrays, or manual DB edits that corrupted the metadata value.","solutions":["Replace the metadata wholesale with a valid object using a direct metadata set (no incremental ops), then apply edits","Migrate the offending rows: read the current value, convert it to an object, write it back","Add a pre-flight check that json.Unmarshal(existing, &map[string]any{}) succeeds before doing incremental edits"],"exampleFix":"// before\n// existing metadata: [\"a\",\"b\"] -> edit fails\n\n// after\n// one-time migration: set metadata to {\"items\": [\"a\",\"b\"]} via full replacement,\n// then run incremental set/unset ops against the object","handlingStrategy":"type-guard","validationCode":"var probe map[string]json.RawMessage\nif len(issue.Metadata) > 0 && string(bytes.TrimSpace(issue.Metadata)) != \"null\" {\n    if err := json.Unmarshal(issue.Metadata, &probe); err != nil {\n        return errors.New(\"metadata must be replaced with a JSON object before incremental edits\")\n    }\n}","typeGuard":"func isMetadataObject(raw json.RawMessage) bool {\n    trimmed := strings.TrimSpace(string(raw))\n    if trimmed == \"\" || trimmed == \"null\" { return true }\n    var m map[string]json.RawMessage\n    return json.Unmarshal([]byte(trimmed), &m) == nil\n}","tryCatchPattern":"if err := issueops.ResolveMergeOps(issue, updates, resolved); err != nil {\n    if strings.Contains(err.Error(), \"existing metadata is not a JSON object\") {\n        // perform full replacement with a valid object, then re-apply edits\n    }\n}","preventionTips":["Run a migration converting legacy non-object metadata to objects","Reject non-object metadata at ingestion/import time","Use isMetadataObject as a gate before any incremental metadata op"],"tags":["metadata","json","data-integrity"],"backgroundTag":"metadata-not-json-object","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}