{"record":{"id":"7a27505a9f1243af","repo":"gastownhall/beads","slug":"failed-to-encode-slot-metadata-w","errorCode":null,"errorMessage":"failed to encode slot metadata: %w","messagePattern":"failed to encode slot metadata: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/merge_slot.go","lineNumber":118,"sourceCode":"\t\t\tmeta := parseSlotMeta(slot)\n\t\t\tresult.Holder = meta.Holder\n\n\t\t\tif slot.Status != types.StatusOpen {\n\t\t\t\t// Slot is held.\n\t\t\t\tif wait {\n\t\t\t\t\talreadyWaiting := false\n\t\t\t\t\tfor _, w := range meta.Waiters {\n\t\t\t\t\t\tif w == holder {\n\t\t\t\t\t\t\talreadyWaiting = true\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif !alreadyWaiting {\n\t\t\t\t\t\tmeta.Waiters = append(meta.Waiters, holder)\n\t\t\t\t\t}\n\t\t\t\t\tmetaStr, err := encodeSlotMeta(meta)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to encode slot metadata: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t\tif err := tx.UpdateIssue(ctx, slot.ID, map[string]interface{}{\"metadata\": metaStr}, actor); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to add to waiters: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t\tresult.Waiting = true\n\t\t\t\t\tresult.Position = len(meta.Waiters)\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// Slot is available — acquire it atomically.\n\t\t\tnewMeta := slotMeta{Holder: holder, Waiters: meta.Waiters}\n\t\t\tmetaStr, err := encodeSlotMeta(newMeta)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to encode slot metadata: %w\", err)\n\t\t\t}\n\t\t\tif err := tx.UpdateIssue(ctx, slot.ID, map[string]interface{}{\n\t\t\t\t\"status\":   types.StatusInProgress,","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/merge_slot.go#L100-L136","documentation":"This error wraps a failure to JSON-serialize the merge slot's metadata (holder + waiters list) via encodeSlotMeta while adding a waiter inside MergeSlotAcquireImpl. The slot state lives in the issue's Metadata field, so if json.Marshal fails the waiter cannot be registered and the acquire transaction aborts. In practice this is nearly impossible since slotMeta only contains a string and a []string.","triggerScenarios":"Calling MergeSlotAcquire with wait=true while the slot is held causes the code to append the holder to meta.Waiters and call encodeSlotMeta; the error fires only if json.Marshal of slotMeta fails (e.g. a custom-marshaled corrupted meta or an unmarshalable value injected via MarshalJSON in future changes).","commonSituations":"Practically never hit by users of the library; seen only during development when the slotMeta struct gains unmarshalable fields or when store metadata is corrupted by a version mismatch.","solutions":["Retry the acquire — the failure is transient/infrastructural, not data-related","Check that the slot bead's metadata is well-formed JSON via bd show <slot-id>","If reproducible, report a bug: json.Marshal of slotMeta should never fail"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"meta := slotMeta{Holder: h, Waiters: ws}\nif _, err := json.Marshal(meta); err != nil { return fmt.Errorf(\"slot meta unmarshalable: %w\", err) }","typeGuard":null,"tryCatchPattern":"for i := 0; i < 3; i++ {\n    res, err := store.MergeSlotAcquire(ctx, holder, actor, true)\n    if err == nil || !strings.Contains(err.Error(), \"failed to encode slot metadata\") { break }\n    time.Sleep(backoff(i))\n}","preventionTips":["Keep slotMeta limited to JSON-marshalable fields (string, []string)","Treat any occurrence as a bug and file it — json.Marshal of this struct should never fail","Log the wrapped error (%w) to capture the root marshal cause"],"tags":["go","merge-slot","json-serialization","storage"],"backgroundTag":"slot-metadata-encode-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}