{"record":{"id":"b2b9634f65767707","repo":"gastownhall/beads","slug":"failed-to-get-rows-affected-w-b2b963","errorCode":null,"errorMessage":"failed to get rows affected: %w","messagePattern":"failed to get rows affected: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/claim.go","lineNumber":134,"sourceCode":"\t\t\t\tSET assignee = ?, status = 'in_progress', updated_at = ?, started_at = ?, %s\n\t\t\t\tWHERE id = ? AND row_lock = ? AND status IN (%s)\n\t\t\t`, issueTable, rowLockClause, statusPlaceholders), args...)\n\t\t} else {\n\t\t\targs := append([]interface{}{actor, now}, rowLockArgs...)\n\t\t\targs = append(args, id, oldIssue.RowVersion)\n\t\t\targs = append(args, statusArgs...)\n\t\t\tresult, err = tx.ExecContext(ctx, fmt.Sprintf(`\n\t\t\t\tUPDATE %s\n\t\t\t\tSET assignee = ?, status = 'in_progress', updated_at = ?, %s\n\t\t\t\tWHERE id = ? AND row_lock = ? AND status IN (%s)\n\t\t\t`, issueTable, rowLockClause, statusPlaceholders), args...)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to claim issue: %w\", err)\n\t\t}\n\t\trowsAffected, err = result.RowsAffected()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get rows affected: %w\", err)\n\t\t}\n\t}\n\n\tif rowsAffected == 0 {\n\t\tassignee, currentStatus, err := readClaimStateInTx(ctx, tx, issueTable, id)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get current claim state: %w\", err)\n\t\t}\n\t\t// Idempotent: if already claimed in_progress by the same actor —\n\t\t// including a spelling difference across layers (ga-wzl83) — treat as\n\t\t// success. This supports agent retry workflows where claim may be\n\t\t// called multiple times after transient failures (GH#8).\n\t\tif actorMatches(assignee, actor) && currentStatus == types.StatusInProgress {\n\t\t\treturn &ClaimResult{OldIssue: oldIssue, IsWisp: isWisp}, nil\n\t\t}\n\t\t// The refusal carries the state that lost the CAS, read just above in\n\t\t// THIS transaction, so a caller learns who won without parsing the\n\t\t// message. The typed wrapper carries the fields; the PROSE is composed","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/claim.go#L116-L152","documentation":"After the claim UPDATE succeeds as SQL, ClaimIssueInTx calls result.RowsAffected() to decide whether the CAS won. If the driver cannot report the affected-row count, this error wraps that failure. It indicates a driver/driver-backend limitation rather than a claim conflict.","triggerScenarios":"tx.ExecContext succeeded but result.RowsAffected() returned an error on the CAS UPDATE in ClaimIssueInTx — typically with drivers or proxy setups that don't implement RowsAffected, or a connection that dropped between exec and stat.","commonSituations":"Using a non-standard SQL driver or connection pooler in front of Dolt that doesn't propagate affected-row metadata; flaky connection dying between ExecContext and RowsAffected.","solutions":["Re-run the claim; a same-actor in_progress re-claim is idempotent","Verify the storage driver is the supported dolthub/driver path, not a shim","Check connection stability to the database server"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// use the supported dolthub driver, not a shim; verify with bd doctor\n// no pre-call check can detect RowsAffected support; treat as infra health issue","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"failed to get rows affected\") {\n    return retryClaim(ctx, id, actor) // claim CAS is idempotent for same actor\n}","preventionTips":["Stick to the supported storage driver (dolthub/driver) for the Dolt backend","Avoid poolers/proxies that strip result metadata between exec and stat","Retry once on this error before surfacing it — state is unchanged"],"tags":["database","driver","storage"],"backgroundTag":"database-driver-error","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}