{"record":{"id":"eb66f5e6476869c8","repo":"gastownhall/beads","slug":"failed-to-get-rows-affected-w-eb66f5","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/close.go","lineNumber":350,"sourceCode":"\n\tnow := time.Now().UTC()\n\n\t// row_lock is rewritten on close so a concurrent reclaim (which also rewrites\n\t// row_lock) collides on this cell and is forced to conflict-and-retry rather\n\t// than silently cell-merging a revert-to-ready over a completed close (see\n\t// lease.go). The lease row is deleted below: a closed issue holds no lease.\n\tresult, err := tx.ExecContext(ctx, fmt.Sprintf(`\n\t\tUPDATE %s SET status = ?, closed_at = ?, updated_at = ?, close_reason = ?, closed_by_session = ?,\n\t\t\trow_lock = ?\n\t\tWHERE id = ? AND status != ?\n\t`, issueTable), types.StatusClosed, now, now, reason, session, freshRowLock(), id, types.StatusClosed)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to close issue: %w\", err)\n\t}\n\n\trows, err := result.RowsAffected()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get rows affected: %w\", err)\n\t}\n\tif rows == 0 {\n\t\tvar status string\n\t\tqerr := tx.QueryRowContext(ctx,\n\t\t\tfmt.Sprintf(`SELECT status FROM %s WHERE id = ?`, issueTable), id,\n\t\t).Scan(&status)\n\t\tif qerr == sql.ErrNoRows {\n\t\t\treturn nil, fmt.Errorf(\"%w: issue %s\", storage.ErrNotFound, id)\n\t\t}\n\t\tif qerr != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to check issue existence: %w\", qerr)\n\t\t}\n\t\tif types.Status(status) == types.StatusClosed {\n\t\t\treturn &CloseResult{IsWisp: isWisp, AlreadyClosed: true}, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"failed to close issue: %s\", id)\n\t}\n","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/close.go#L332-L368","documentation":"This error is returned when result.RowsAffected() — used to detect whether the close UPDATE actually matched a row — fails at the driver level. Beads relies on the affected-row count to distinguish 'closed' from 'issue not found / already closed', so a failure here aborts the close. The root driver error is preserved with %w.","triggerScenarios":"tx.ExecContext succeeded but result.RowsAffected() returns an error: unsupported by the driver for the statement type, driver/connection error after executing, or a driver implementation that cannot report rows affected.","commonSituations":"Using a driver or proxy (e.g. an unusual Dolt/MySQL proxy) that doesn't implement the affected-rows protocol correctly; connection reset right after the UPDATE; custom driver in the storage boundary that doesn't support RowsAffected.","solutions":["Check which storage driver is in use; ensure it is the supported dolthub/driver interface and not a proxy that drops affected-rows metadata.","Retry the close operation with a fresh transaction and connection.","Update the driver/storage layer if running an old or patched driver version.","If reproducible, capture the wrapped error and report it — this path should never fail with a healthy driver."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// ensure a supported driver is configured\nif !isSupportedStorageDriver(cfg.Driver) {\n    return fmt.Errorf(\"unsupported storage driver %q: RowsAffected may not be available\", cfg.Driver)\n}","typeGuard":null,"tryCatchPattern":"err := store.CloseIssue(ctx, id, actor, reason)\nif err != nil && strings.Contains(err.Error(), \"failed to get rows affected\") {\n    // retry once; if persistent, driver is broken — report it\n    return retryClose(ctx, id, actor, reason, 1)\n}","preventionTips":["Use the supported dolthub/driver storage interface, not proxies or custom drivers.","Keep the driver updated to a version known to report affected rows.","Treat repeated occurrences as a driver bug and file an issue with the wrapped error.","Avoid layers that rewrite or intercept the wire protocol between beads and the database."],"tags":["database","driver","rows-affected","sql"],"backgroundTag":"rows-affected-unsupported","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}