-
Notifications
You must be signed in to change notification settings - Fork 63
Open
Description
Description
When using @powersync/node with better-sqlite3, the execute() method returns rowsAffected: 0 even when an UPDATE statement successfully modifies rows.
Environment
@powersync/node: latest (installed Feb 2026)better-sqlite3: 12.6.2- Node.js: v22.x
- OS: macOS (arm64)
Reproduction
import { PowerSyncDatabase } from "@powersync/node";
// After connecting and syncing...
// 1. Create a task
await db.execute(
"INSERT INTO tasks (id, title, deleted_at) VALUES (?, ?, NULL)",
[taskId, "Test task"]
);
// 2. Verify task exists
const existing = await db.getOptional(
"SELECT deleted_at FROM tasks WHERE id = ?",
[taskId]
);
console.log(existing); // { deleted_at: null } ✓
// 3. Update the task
const result = await db.execute(
"UPDATE tasks SET deleted_at = ? WHERE id = ? AND deleted_at IS NULL",
[new Date().toISOString(), taskId]
);
console.log(result);
// Actual: { rowsAffected: 0, insertId: 2147483647 }
// Expected: { rowsAffected: 1, insertId: ... }
// 4. But the update DID work
const check = await db.getOptional(
"SELECT deleted_at FROM tasks WHERE id = ?",
[taskId]
);
console.log(check); // { deleted_at: "2026-02-24T..." } ✓Observed Behavior
rowsAffectedis0even though the UPDATE succeededinsertIdis2147483647(INT_MAX / 0x7FFFFFFF) — suggests uninitialized or sentinel value- The row IS actually updated (verified by subsequent SELECT)
Expected Behavior
rowsAffectedshould be1(or the actual count of affected rows)insertIdshould be a valid value or undefined for UPDATE statements
Possible Cause
The Node SDK uses a worker thread for SQLite operations. The result metadata (rowsAffected) may not be correctly marshalled back from the worker thread to the main thread.
Workaround
We implemented a workaround by verifying the operation with a follow-up SELECT instead of trusting rowsAffected:
await db.execute("UPDATE tasks SET deleted_at = ? WHERE id = ?", [now, id]);
// Verify instead of trusting rowsAffected
const check = await db.getOptional("SELECT deleted_at FROM tasks WHERE id = ?", [id]);
return check?.deleted_at !== null;Impact
Any code relying on rowsAffected to confirm UPDATE/DELETE success will incorrectly think the operation failed.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels