{"record":{"id":"d9204ed8bf43ae9f","repo":"gastownhall/beads","slug":"failed-to-record-claim-event-w","errorCode":null,"errorMessage":"failed to record claim event: %w","messagePattern":"failed to record claim event: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/claim.go","lineNumber":216,"sourceCode":"\t// stops heartbeating and bd reclaim later reverts the issue. Lease rows\n\t// live in the ephemeral leases table (no Dolt commit, node-local). Wisps\n\t// are never leased (they are ephemeral, not reclaimable work).\n\tif !isWisp {\n\t\tif err := UpsertLeaseInTx(ctx, tx, id, actor, now, leaseTTL(ctx)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Record the claim event.\n\toldData, _ := json.Marshal(oldIssue)\n\tnewUpdates := map[string]interface{}{\n\t\t\"assignee\": actor,\n\t\t\"status\":   \"in_progress\",\n\t}\n\tnewData, _ := json.Marshal(newUpdates)\n\n\tif err := RecordFullEventInTable(ctx, tx, eventTable, id, types.EventClaimed, actor, string(oldData), string(newData)); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to record claim event: %w\", err)\n\t}\n\n\t// A claim changes assignee and status, so it journals as an update. The\n\t// idempotent re-claim path returns above without writing and journals\n\t// nothing.\n\tif err := RecordEventInTx(ctx, tx, EventUpdate, id, actor); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &ClaimResult{OldIssue: oldIssue, IsWisp: isWisp}, nil\n}\n\n// readClaimStateInTx reads one row's coordination columns inside tx — the\n// state a lost compare-and-set reports. Shared by the CAS itself and by the\n// public claim role, so the two cannot disagree about what \"the state that\n// refused this claim\" means.\n//\n//nolint:gosec // G201: issueTable comes from WispTableRouting (hardcoded constants)","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/claim.go#L198-L234","documentation":"After a successful claim CAS, ClaimIssueInTx journals a claimed event via RecordFullEventInTable (old/new JSON snapshots) inside the same transaction. This error wraps any failure of that journal write. The claim's row update may be rolled back with the transaction since the event write failed.","triggerScenarios":"RecordFullEventInTable fails during ClaimIssueInTx — event table missing/corrupt, connection drop mid-transaction, context cancellation, or constraint failure writing the event JSON payload.","commonSituations":"Interrupted CLI run (canceled context) right after the CAS won; corrupted or migrated-away event table; very large issue JSON exceeding limits on an embedded backend.","solutions":["Retry the claim — the CAS is idempotent for the same actor once in_progress","Check the event table integrity and DB connectivity (bd doctor)","Inspect the wrapped driver error for the specific SQL cause"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// verify DB health before claim bursts\nif err := db.PingContext(ctx); err != nil { return err }","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"failed to record claim event\") {\n    return retryClaim(ctx, id, actor) // idempotent for same actor\n}","preventionTips":["Don't cancel claim contexts mid-flight; use generous deadlines","Keep event tables intact across migrations (bd doctor can check)","Retry the claim — the CAS succeeded or rolled back atomically with the event"],"tags":["database","event-journal","storage","claim"],"backgroundTag":"event-journal-write-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}