{"record":{"id":"e2722b68b0cff2da","repo":"gastownhall/beads","slug":"add-label-s-on-s-w-e2722b","errorCode":null,"errorMessage":"add label '%s' on %s: %w","messagePattern":"add label '(.+?)' on (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/label_proxied_server.go","lineNumber":189,"sourceCode":"\t\t// ga-2ltro.12 deleted from `bd tag`, `bd set-state` and the molecule\n\t\t// port — the branch a front door can get backwards and put a wisp's\n\t\t// label in the durable table. It survives because propagate is a search\n\t\t// plus a fan-out that must land as ONE transaction over N children, and\n\t\t// a per-child Lifecycle.Update is N transactions: the atomicity this\n\t\t// command has today would be the price of the migration. The shape that\n\t\t// keeps both is issueops.BatchApplier.ApplyBatch with one ItemUpdate per\n\t\t// child carrying this same label patch, and it is blocked on a cmd/bd\n\t\t// accessor for that role. That is the follow-up this waiver names\n\t\t// (ga-2ltro.12); it is the last one on this list that WRITES.\n\t\tfor _, child := range children {\n\t\t\tvar e error\n\t\t\tif child.Ephemeral {\n\t\t\t\te = uw.LabelUseCase().AddWispLabel(ctx, child.ID, label, actor) //nolint:forbidigo // atomic N-child fan-out; awaits a BatchApplier accessor\n\t\t\t} else {\n\t\t\t\te = uw.LabelUseCase().AddLabel(ctx, child.ID, label, actor) //nolint:forbidigo // atomic N-child fan-out; awaits a BatchApplier accessor\n\t\t\t}\n\t\t\tif e != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"add label '%s' on %s: %w\", label, child.ID, e)\n\t\t\t}\n\t\t}\n\t\treturn fmt.Sprintf(\"bd: propagate label '%s' from %s to %d children\", label, parentID, len(children)), nil\n\t})\n\tif err != nil {\n\t\treturn HandleErrorRespectJSON(\"label propagate: %v\", err)\n\t}\n\n\tif len(children) == 0 {\n\t\tif jsonOutput {\n\t\t\treturn outputJSON([]map[string]interface{}{})\n\t\t}\n\t\tfmt.Printf(\"No children found for %s\\n\", parentID)\n\t\treturn nil\n\t}\n\tcommandDidWrite.Store(true)\n\n\tif jsonOutput {","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/label_proxied_server.go#L171-L207","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the wrapped error to see which child ID failed and why","Fix the storage issue, then re-run propagation — label application is idempotent so already-labeled children are safe","If a child was deleted, refresh the parent's children list before retrying"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// ensure the child still exists before fanning out\nfor _, child := range children {\n    if _, err := uw.IssueUseCase().GetIssue(ctx, child.ID); err != nil {\n        return fmt.Errorf(\"child %s missing: %w\", child.ID, err)\n    }\n}","typeGuard":"func isNotFound(err error) bool { return errors.Is(err, storage.ErrNotFound) }","tryCatchPattern":"if e := uw.LabelUseCase().AddLabel(ctx, child.ID, label, actor); e != nil {\n    if isNotFound(e) { continue } // child vanished; skip\n    return fmt.Errorf(\"add label '%s' on %s: %w\", label, child.ID, e)\n}","preventionTips":["Run label propagation serially per workspace to avoid lock contention","Treat fan-out as idempotent and safe to re-run after partial failure","Refresh the children list immediately before propagation to avoid stale IDs"],"tags":["storage","labels","fan-out","partial-failure"],"backgroundTag":"label-write-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}