{"record":{"id":"285a793d86487950","repo":"gastownhall/beads","slug":"db-claim-s-read-old-issue-w","errorCode":null,"errorMessage":"db: Claim %s: read old issue: %w","messagePattern":"db: Claim (.+?): read old issue: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/issue.go","lineNumber":405,"sourceCode":"\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc (r *issueSQLRepositoryImpl) Claim(ctx context.Context, id, actor string, opts domain.IssueTableOpts) (domain.ClaimRowResult, error) {\n\tif id == \"\" {\n\t\treturn domain.ClaimRowResult{}, errors.New(\"db: Claim: id must not be empty\")\n\t}\n\t// The CAS below writes assignee = actor. actor is user-settable (--actor /\n\t// BEADS_ACTOR), so bound it against the VARCHAR(255) assignee column up front\n\t// and return a typed ErrFieldTooLong rather than a raw backend error.\n\tif err := types.CheckFieldLen(\"actor\", actor); err != nil {\n\t\treturn domain.ClaimRowResult{}, err\n\t}\n\n\toldIssue, err := r.Get(ctx, id, opts)\n\tif err != nil {\n\t\treturn domain.ClaimRowResult{}, fmt.Errorf(\"db: Claim %s: read old issue: %w\", id, err)\n\t}\n\n\ttable := pickIssueTable(opts.UseWispsTable)\n\tnow := time.Now().UTC()\n\tstartedWasZero := oldIssue.StartedAt == nil\n\n\t// Rewrite row_lock exactly like the primary claim path (issueops.\n\t// ClaimIssueInTx). Without this, a claim made through the proxied-server\n\t// (uow) path leaves row_lock unchanged — open to the cell-merge bug the\n\t// row_lock invariant guards against (see issueops/lease.go). The lease\n\t// itself is granted into the ephemeral leases table below, after the CAS.\n\trowLockClause, rowLockArgs := issueops.RowLockClause()\n\n\t// Mirror the primary path's pool-aware predicate (bd-bguz6): aliases in\n\t// the claim.pools config are claimable by any actor. This dual must stay\n\t// in lockstep with issueops.ClaimIssueInTx — the lease comment above is\n\t// the scar from the last time it drifted.\n\tpools, err := issueops.ClaimPoolAliasesInTx(ctx, r.runner)","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/issue.go#L387-L423","documentation":"This error wraps a failure to read the current (pre-claim) issue via Get at the start of Claim. Claim needs the old issue snapshot to validate claimability and journal old/new values; if Get fails, Claim aborts with this wrapped error.","triggerScenarios":"Calling Claim(id, actor, opts) for a nonexistent id (ErrNotFound from Get), with wrong UseWispsTable routing, or when the underlying read query fails (connection error, context canceled).","commonSituations":"Claiming a deleted or mistyped issue id; stale ids from another repo or cache; database unavailable; wisp vs issues table mismatch.","solutions":["Check the wrapped cause: if ErrNotFound, verify the issue exists (bd show <id>).","Fix id typos or stale references before claiming.","Verify UseWispsTable routing matches where the issue lives.","Retry if the cause is a transient connection/context error."],"exampleFix":"// before\nres, err := store.Claim(ctx, id, actor, opts) // fails with confusing wrapped error\n// after\nif _, err := store.Get(ctx, id, opts); err != nil {\n    return fmt.Errorf(\"issue %s not claimable: %w\", id, err)\n}\nres, err := store.Claim(ctx, id, actor, opts)","handlingStrategy":"validation","validationCode":"issue, err := store.Get(ctx, id, opts)\nif err != nil { return err } // fail fast: nonexistent id or bad routing\n_ = issue","typeGuard":"func claimable(ctx context.Context, s Store, id string, opts Options) bool {\n    _, err := s.Get(ctx, id, opts)\n    return err == nil\n}","tryCatchPattern":"res, err := store.Claim(ctx, id, actor, opts)\nif err != nil {\n    if errors.Is(err, domain.ErrNotFound) { /* refresh issue list, skip id */ }\n    return err\n}","preventionTips":["Always verify the id exists before claiming (bd show <id>).","Pass the same opts (UseWispsTable) used when the issue was created.","Refresh local caches of issue ids before claim loops.","Handle ErrNotFound explicitly rather than retrying blindly."],"tags":["database","claim","not-found"],"backgroundTag":"issue-not-found","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}