gastownhall/beads · error

add label '%s' on %s: %w

Error message

add label '%s' on %s: %w

What it means

Wraps a failure from AddLabel or AddWispLabel when propagating a label from a parent issue to one of its children. The fan-out loop applies the label per child; if any child write fails, the error identifies the label, the child ID, and the root cause via %w. Note the partial-failure property: earlier children may already have the label.

Source

Thrown at cmd/bd/label_proxied_server.go:189

		// ga-2ltro.12 deleted from `bd tag`, `bd set-state` and the molecule
		// port — the branch a front door can get backwards and put a wisp's
		// label in the durable table. It survives because propagate is a search
		// plus a fan-out that must land as ONE transaction over N children, and
		// a per-child Lifecycle.Update is N transactions: the atomicity this
		// command has today would be the price of the migration. The shape that
		// keeps both is issueops.BatchApplier.ApplyBatch with one ItemUpdate per
		// child carrying this same label patch, and it is blocked on a cmd/bd
		// accessor for that role. That is the follow-up this waiver names
		// (ga-2ltro.12); it is the last one on this list that WRITES.
		for _, child := range children {
			var e error
			if child.Ephemeral {
				e = uw.LabelUseCase().AddWispLabel(ctx, child.ID, label, actor) //nolint:forbidigo // atomic N-child fan-out; awaits a BatchApplier accessor
			} else {
				e = uw.LabelUseCase().AddLabel(ctx, child.ID, label, actor) //nolint:forbidigo // atomic N-child fan-out; awaits a BatchApplier accessor
			}
			if e != nil {
				return "", fmt.Errorf("add label '%s' on %s: %w", label, child.ID, e)
			}
		}
		return fmt.Sprintf("bd: propagate label '%s' from %s to %d children", label, parentID, len(children)), nil
	})
	if err != nil {
		return HandleErrorRespectJSON("label propagate: %v", err)
	}

	if len(children) == 0 {
		if jsonOutput {
			return outputJSON([]map[string]interface{}{})
		}
		fmt.Printf("No children found for %s\n", parentID)
		return nil
	}
	commandDidWrite.Store(true)

	if jsonOutput {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped error to see which child ID failed and why
  2. Fix the storage issue, then re-run propagation — label application is idempotent so already-labeled children are safe
  3. If a child was deleted, refresh the parent's children list before retrying
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure the child still exists before fanning out
for _, child := range children {
    if _, err := uw.IssueUseCase().GetIssue(ctx, child.ID); err != nil {
        return fmt.Errorf("child %s missing: %w", child.ID, err)
    }
}

Type guard

func isNotFound(err error) bool { return errors.Is(err, storage.ErrNotFound) }

Try / catch

if e := uw.LabelUseCase().AddLabel(ctx, child.ID, label, actor); e != nil {
    if isNotFound(e) { continue } // child vanished; skip
    return fmt.Errorf("add label '%s' on %s: %w", label, child.ID, e)
}

Prevention

When it happens

Trigger: Running label propagation where child.Ephemeral routes to AddWispLabel (or AddLabel for normal issues) and that use-case call returns an error — storage write failure, concurrent modification, or the child issue no longer existing.

Common situations: Database locked/unavailable during a multi-child fan-out; child deleted between the SearchIssues listing and the write; permission or actor validation failures on AddLabel.

Related errors


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