gastownhall/beads · error

failed to encode slot metadata: %w

Error message

failed to encode slot metadata: %w

What it means

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.

Source

Thrown at internal/storage/merge_slot.go:118

			meta := parseSlotMeta(slot)
			result.Holder = meta.Holder

			if slot.Status != types.StatusOpen {
				// Slot is held.
				if wait {
					alreadyWaiting := false
					for _, w := range meta.Waiters {
						if w == holder {
							alreadyWaiting = true
							break
						}
					}
					if !alreadyWaiting {
						meta.Waiters = append(meta.Waiters, holder)
					}
					metaStr, err := encodeSlotMeta(meta)
					if err != nil {
						return fmt.Errorf("failed to encode slot metadata: %w", err)
					}
					if err := tx.UpdateIssue(ctx, slot.ID, map[string]interface{}{"metadata": metaStr}, actor); err != nil {
						return fmt.Errorf("failed to add to waiters: %w", err)
					}
					result.Waiting = true
					result.Position = len(meta.Waiters)
				}
				return nil
			}

			// Slot is available — acquire it atomically.
			newMeta := slotMeta{Holder: holder, Waiters: meta.Waiters}
			metaStr, err := encodeSlotMeta(newMeta)
			if err != nil {
				return fmt.Errorf("failed to encode slot metadata: %w", err)
			}
			if err := tx.UpdateIssue(ctx, slot.ID, map[string]interface{}{
				"status":   types.StatusInProgress,

View on GitHub (pinned to 71377f2769)

Solutions

  1. Retry the acquire — the failure is transient/infrastructural, not data-related
  2. Check that the slot bead's metadata is well-formed JSON via bd show <slot-id>
  3. If reproducible, report a bug: json.Marshal of slotMeta should never fail
Defensive patterns

Strategy: retry

Validate before calling

meta := slotMeta{Holder: h, Waiters: ws}
if _, err := json.Marshal(meta); err != nil { return fmt.Errorf("slot meta unmarshalable: %w", err) }

Try / catch

for i := 0; i < 3; i++ {
    res, err := store.MergeSlotAcquire(ctx, holder, actor, true)
    if err == nil || !strings.Contains(err.Error(), "failed to encode slot metadata") { break }
    time.Sleep(backoff(i))
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/7a27505a9f1243af. Report an issue: GitHub.