{"record":{"id":"bd5b8549670217ca","repo":"gastownhall/beads","slug":"metadata-edit-failed-w","errorCode":null,"errorMessage":"metadata edit failed: %w","messagePattern":"metadata edit failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/update.go","lineNumber":912,"sourceCode":"\t}\n\tif hasSet || hasUnset {\n\t\tunset, err := mergeOpStrings(OpUnsetMetadata, updates[OpUnsetMetadata], hasUnset)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tvar merged json.RawMessage\n\t\tif set, typed := updates[OpSetMetadata].(map[string]json.RawMessage); typed {\n\t\t\tmerged, err = applyTypedMetadataEdits(current, set, unset)\n\t\t} else {\n\t\t\tvar set []string\n\t\t\tset, err = mergeOpStrings(OpSetMetadata, updates[OpSetMetadata], hasSet)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tmerged, err = storage.ApplyMetadataEdits(current, set, unset)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"metadata edit failed: %w\", err)\n\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 {","sourceCodeStart":894,"sourceCodeEnd":930,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/update.go#L894-L930","documentation":"Applying incremental set/unset metadata edits via storage.ApplyMetadataEdits failed. This wraps any error from applying the typed key/value edits to the current metadata document after the merge step.","triggerScenarios":"Calling an update with OpSetMetadata/OpUnsetMetadata where ApplyMetadataEdits fails — typically a key violating ValidateMetadataKey rules or an incompatible existing document.","commonSituations":"Using metadata keys with illegal characters or reserved prefixes, or applying set/unset edits to metadata that is not a JSON object.","solutions":["Check each key with storage.ValidateMetadataKey (or the equivalent CLI rules) before submitting","Ensure the existing metadata is a valid JSON object; repair it with a full replacement first","Read the wrapped %w cause for the specific key or document failure"],"exampleFix":"// before\nupdates[issueops.OpSetMetadata] = map[string]json.RawMessage{\"bad key!\": json.RawMessage(`1`)}\n\n// after\nupdates[issueops.OpSetMetadata] = map[string]json.RawMessage{\"priority\": json.RawMessage(`1`) // key passes ValidateMetadataKey\n}","handlingStrategy":"validation","validationCode":"for key := range set {\n    if err := storage.ValidateMetadataKey(key); err != nil {\n        return fmt.Errorf(\"skip update, invalid metadata key %q: %w\", key, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := issueops.ResolveMergeOps(issue, updates, resolved); err != nil {\n    if strings.Contains(err.Error(), \"metadata edit failed\") {\n        return fmt.Errorf(\"metadata set/unset rejected: %w\", err)\n    }\n}","preventionTips":["Pre-validate every metadata key against ValidateMetadataKey","Confirm existing metadata is an object before set/unset edits","Keep keys alphanumeric/dash/underscore to stay within rules"],"tags":["metadata","validation","json"],"backgroundTag":"metadata-edit-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}