{"record":{"id":"4cd0ca52cb901381","repo":"gastownhall/beads","slug":"parsing-metadata-for-s-w","errorCode":null,"errorMessage":"parsing metadata for %s: %w","messagePattern":"parsing metadata for (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/slots.go","lineNumber":102,"sourceCode":"\t}\n\treturn s.MergeMetadata(ctx, issueID, key, raw, actor)\n}\n\n// SlotGet retrieves the value of a metadata key from an issue.\n// Returns an error if the issue has no metadata or the key is not found.\nfunc (s *DoltStore) SlotGet(ctx context.Context, issueID, key string) (string, error) {\n\tissue, err := s.GetIssue(ctx, issueID)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting issue %s: %w\", issueID, err)\n\t}\n\n\tif len(issue.Metadata) == 0 {\n\t\treturn \"\", fmt.Errorf(\"no slot %q on %s: no metadata\", key, issueID)\n\t}\n\n\tmetadata := make(map[string]interface{})\n\tif err := json.Unmarshal(issue.Metadata, &metadata); err != nil {\n\t\treturn \"\", fmt.Errorf(\"parsing metadata for %s: %w\", issueID, err)\n\t}\n\n\tval, ok := metadata[key]\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"no slot %q on %s: key not found\", key, issueID)\n\t}\n\n\tswitch v := val.(type) {\n\tcase string:\n\t\treturn v, nil\n\tdefault:\n\t\t// Non-string values are returned as JSON\n\t\traw, err := json.Marshal(v)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"marshaling slot value for %s.%s: %w\", issueID, key, err)\n\t\t}\n\t\treturn string(raw), nil\n\t}","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/slots.go#L84-L120","documentation":"The issue's metadata column contains data, but it is not valid JSON or not a JSON object, so json.Unmarshal into map[string]interface{} failed. The library treats metadata as a JSON object of slots; corrupt or unexpected content triggers this wrap with the issue ID.","triggerScenarios":"SlotGet on an issue whose metadata blob was written by an older schema version, hand-edited, or corrupted so json.Unmarshal fails.","commonSituations":"Manual UPDATE of the metadata column with malformed JSON; migration from another tracker leaving non-object JSON (e.g. a bare string or array); partial write from a crashed older version.","solutions":["Inspect the issue's metadata column and repair it to a valid JSON object (e.g. UPDATE issues SET metadata='{}' ...).","Re-set all slots with SlotSet to rewrite clean JSON.","If migrating data, sanitize metadata JSON before import."],"exampleFix":"// before\nUPDATE issues SET metadata = '{owner: alice}' WHERE id = 'bd-1';  // invalid JSON\n// after\nUPDATE issues SET metadata = '{\"owner\": \"alice\"}' WHERE id = 'bd-1';","handlingStrategy":"validation","validationCode":"issue, _ := store.GetIssue(ctx, issueID)\nif len(issue.Metadata) > 0 && !json.Valid(issue.Metadata) {\n\t// repair or reject before calling SlotGet\n}","typeGuard":"func metadataIsJSONObject(raw []byte) bool {\n\tvar m map[string]interface{}\n\treturn len(raw) > 0 && json.Unmarshal(raw, &m) == nil\n}","tryCatchPattern":"val, err := store.SlotGet(ctx, id, key)\nif err != nil && strings.Contains(err.Error(), \"parsing metadata\") {\n\t// quarantine the issue's metadata and re-set slots\n}","preventionTips":["Never hand-edit the metadata column; always write via SlotSet/MergeMetadata.","Validate metadata JSON during any migration or import.","Ensure JSON object (not array/scalar) shape when importing from other trackers."],"tags":["json","corrupt-data","metadata","dolt"],"backgroundTag":"invalid-json","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}