{"record":{"id":"afb2790727969cfa","repo":"gastownhall/beads","slug":"step-s-already-claimed-status-s","errorCode":null,"errorMessage":"step %s already claimed (status: %s)","messagePattern":"step (.+?) already claimed \\(status: (.+?)\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/mol_port.go","lineNumber":110,"sourceCode":"// transaction rather than seeing the last committed value.\nfunc (w storeMolWriter) GetConfig(ctx context.Context, key string) (string, error) {\n\tif w.tx != nil {\n\t\treturn w.tx.GetConfig(ctx, key)\n\t}\n\treturn w.DoltStorage.GetConfig(ctx, key)\n}\n\nfunc (w storeMolWriter) ClaimStepIfOpen(ctx context.Context, id, actor string) error {\n\treturn w.DoltStorage.RunInTransaction(ctx, fmt.Sprintf(\"bd: advance to step %s\", id), func(tx storage.Transaction) error {\n\t\tcurrent, err := tx.GetIssue(ctx, id)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif current == nil {\n\t\t\treturn fmt.Errorf(\"step %s not found\", id)\n\t\t}\n\t\tif current.Status != types.StatusOpen {\n\t\t\treturn fmt.Errorf(\"step %s already claimed (status: %s)\", id, current.Status)\n\t\t}\n\t\treturn tx.UpdateIssue(ctx, id, map[string]interface{}{\"status\": types.StatusInProgress}, actor)\n\t})\n}\n\nfunc newStandaloneStoreMolWriter(store storage.DoltStorage) storeMolWriter {\n\treturn storeMolWriter{DoltStorage: store}\n}\n\ntype uowMolReader struct {\n\tuw uow.UnitOfWork\n}\n\nfunc (r uowMolReader) GetIssue(ctx context.Context, id string) (*types.Issue, error) {\n\tissue, isWisp, rerr := workapi.GetIssueOrWisp(ctx, workapi.NewUOWDetailSource(r.uw), id)\n\tif errors.Is(rerr, storage.ErrNotFound) {\n\t\treturn nil, fmt.Errorf(\"issue %s not found\", id)\n\t}","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/mol_port.go#L92-L128","documentation":"The same step-advance transaction only allows claiming a step whose status is `open`. If the issue exists but is already `in_progress`, `closed`, or otherwise non-open, the port returns `step %s already claimed (status: %s)` to signal a concurrent/duplicate claim rather than silently overwriting state.","triggerScenarios":"Two agents or invocations advancing the same molecule step concurrently; re-running a claim script without checking status first; a step that was previously claimed and never reset. `current.Status != types.StatusOpen` triggers the error inside the `RunInTransaction` callback.","commonSituations":"CI retries after a partial failure; parallel workers racing on the same molecule; a human manually started the step (`bd update <id> --status in_progress`) and automation then tries to claim it.","solutions":["Check the step's status first (`bd show <id>`) and skip the claim if it is already in_progress.","Coordinate claim work so only one worker claims a step (the claim itself is transactional — treat this error as 'someone else got it' and move on).","If the step is genuinely stuck, reset its status to open (`bd update <id> --status open`) before re-claiming."],"exampleFix":"// before\n_ = writer.AdvanceToStep(ctx, id, actor) // blind claim, fails if already claimed\n// after\nif step, _ := reader.GetIssue(ctx, id); step != nil && step.Status == types.StatusOpen {\n    err = writer.AdvanceToStep(ctx, id, actor)\n}","handlingStrategy":"validation","validationCode":"// before claiming, check the step is still open\nSTATUS=$(bd show \"$STEP_ID\" --json | jq -r '.status')\n[[ \"$STATUS\" == \"open\" ]] || { echo \"step $STEP_ID is $STATUS, skipping\"; exit 0; }","typeGuard":"func claimable(iss *types.Issue) bool {\n\treturn iss != nil && iss.Status == types.StatusOpen\n}","tryCatchPattern":"if err := advance(ctx, stepID, actor); err != nil && strings.Contains(err.Error(), \"already claimed\") {\n\tlog.Printf(\"step %s taken by another worker; skipping\", stepID)\n\treturn nil // expected in concurrent claiming\n}","preventionTips":["Treat this error as a normal concurrency outcome, not a crash — skip and pick another step.","Check status immediately before claiming to shrink the race window.","Have one coordinator assign steps when many workers target one molecule."],"tags":["cli","concurrency","state-conflict"],"backgroundTag":"already-claimed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}