{"record":{"id":"8df5b55426cdc0a4","repo":"gastownhall/beads","slug":"set-labels-add-s-w","errorCode":null,"errorMessage":"set labels: add %s: %w","messagePattern":"set labels: add (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/label.go","lineNumber":176,"sourceCode":"\tdesired := make(map[string]bool, len(labels))\n\tfor _, l := range labels {\n\t\tif l != \"\" {\n\t\t\tdesired[l] = true\n\t\t}\n\t}\n\texisting := make(map[string]bool, len(current))\n\tfor _, l := range current {\n\t\texisting[l] = true\n\t\tif !desired[l] {\n\t\t\tif err := u.labelRepo.Delete(ctx, id, l, actor, opts); err != nil {\n\t\t\t\treturn fmt.Errorf(\"set labels: remove %s: %w\", l, err)\n\t\t\t}\n\t\t}\n\t}\n\tfor l := range desired {\n\t\tif !existing[l] {\n\t\t\tif err := u.labelRepo.Insert(ctx, id, l, actor, opts); err != nil {\n\t\t\t\treturn fmt.Errorf(\"set labels: add %s: %w\", l, err)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (u *labelUseCaseImpl) GetLabels(ctx context.Context, issueID string) ([]string, error) {\n\treturn u.list(ctx, issueID, false)\n}\n\nfunc (u *labelUseCaseImpl) GetWispLabels(ctx context.Context, wispID string) ([]string, error) {\n\treturn u.list(ctx, wispID, true)\n}\n\nfunc (u *labelUseCaseImpl) list(ctx context.Context, id string, useWisp bool) ([]string, error) {\n\tif id == \"\" {\n\t\treturn nil, fmt.Errorf(\"get labels: id must not be empty\")\n\t}","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/label.go#L158-L194","documentation":"Wraps a failure from labelRepo.Insert during the addition half of setMany (SetLabels / SetWispLabels). After removing unwanted labels, the use case inserts each newly desired label; one of those inserts failed. The failing label is named and previously applied removals/additions are not rolled back.","triggerScenarios":"SetLabels where the desired set contains labels not currently present and Insert of one fails: uniqueness constraint, driver error, concurrent write, missing parent record.","commonSituations":"Desired label list containing duplicates; another process adding the same label between List and Insert; Dolt/driver connectivity failures mid-operation.","solutions":["Check for duplicate labels in the desired slice and dedupe before calling","Inspect the wrapped error for the storage root cause","Retry SetLabels — it recomputes the diff so remaining additions get applied","Serialize concurrent writers on the same issue"],"exampleFix":"// before\nlabels := []string{\"bug\", \"bug\", \"urgent\"}\nstore.SetLabels(ctx, id, labels, actor)\n// after\nslices.Sort(labels); labels = slices.Compact(labels)\nreturn store.SetLabels(ctx, id, labels, actor)","handlingStrategy":"retry","validationCode":"slices.Sort(labels)\nlabels = slices.Compact(labels)\nlabels = slices.DeleteFunc(labels, func(l string) bool { return l == \"\" })","typeGuard":null,"tryCatchPattern":"if err := store.SetLabels(ctx, id, desired, actor); err != nil {\n\tlog.Printf(\"set labels insert failed on %s: %v — retrying\", id, err)\n\ttime.Sleep(backoff)\n\treturn store.SetLabels(ctx, id, desired, actor) // diff recomputed, adds retried\n}","preventionTips":["Dedupe and drop empty strings from the desired label list before calling","Avoid concurrent SetLabels/AddLabels on the same record","Retry the whole SetLabels call rather than replaying individual labels","Check the named label in the error to spot data issues like duplicates"],"tags":["labels","storage","insert-failed","partial-write"],"backgroundTag":"label-insert-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}