-
Notifications
You must be signed in to change notification settings - Fork 60
Description
Bug Report
Environment
- Package: `@powersync/web` v1.29.0
- Database: SQLite WASM (`WASQLiteOpenFactory`)
- Framework: Next.js 16, React 19
- Integration: TanStack DB (`@tanstack/react-db`)
Problem
UPDATE/DELETE mutations randomly fail with:
Error: SQLite Sequence should not be empty
Error occurs in PowerSync worker at line ~16931:
const rs = await tx.execute("SELECT seq FROM sqlite_sequence WHERE name = 'ps_crud'");
if (!rs.rows?.length) {
throw new Error('SQLite Sequence should not be empty');
}
Root Cause
PowerSync's internal ps_crud table uses INTEGER PRIMARY KEY AUTOINCREMENT, which requires a sqlite_sequence entry. The worker checks for
the sequence entry BEFORE inserting, but the entry doesn't exist on a fresh database until the first INSERT.
Race condition:
- Fresh page load → PowerSync initializes →
ps_crudis empty - User triggers update/delete mutation immediately
- PowerSync checks
sqlite_sequenceforps_crudentry - Entry doesn't exist (never inserted yet) → Error thrown
- INSERT never happens → sequence never auto-created
Why It's Intermittent
Scenario 1 (ERROR):
- Fresh load → immediate update/delete
- No prior writes to
ps_crud→ no sequence entry - ❌ Error
Scenario 2 (WORKS):
- Fresh load → background sync runs first
- Sync writes to
ps_crud→ SQLite auto-creates sequence entry - User triggers mutation
- ✅ Works (sequence exists)
INSERT operations work fine because they're usually slower (user fills form). UPDATE/DELETE happen immediately (single button click),
so they race the background sync.
Reproduction
import { PowerSyncDatabase } from '@powersync/web';
import { powerSyncCollectionOptions } from '@tanstack/react-db';
// 1. Initialize PowerSync (fresh IndexedDB)
const db = new PowerSyncDatabase({ schema, database: factory });
await db.init();
// 2. Create TanStack collection
const collection = createCollection(
powerSyncCollectionOptions({
db,
table: schema.tables.items
})
);
// 3. Immediately trigger update/delete (before any inserts)
const tx = collection.update('item-1', (draft) => {
draft.name = 'Updated';
});
await tx.isPersisted.promise; // ❌ Error: SQLite Sequence should not be emptyMy Workaround
I pre-seed the sqlite_sequence table before mutations:
// Utility with WeakSet caching
const seededDatabases = new WeakSet<PowerSyncDatabase>();
export async function ensurePsCrudSequence(db: PowerSyncDatabase) {
if (seededDatabases.has(db)) return;
await db.database.execute(
"INSERT OR IGNORE INTO sqlite_sequence(name, seq) VALUES('ps_crud', 0)"
);
seededDatabases.add(db);
}
// Before every update/delete mutation:
await ensurePsCrudSequence(db);
collection.update(id, (draft) => { ... });This works, but I'm unsure if:
- Is this expected behavior? Should we manually seed the sequence?
- Should PowerSync handle this internally? Either:
- Don't check sequence before first write (let SQLite auto-create)
- OR seed sequence during
db.init()
- Is there a better approach? Are we missing a configuration option?
Expected Behavior
Update/delete mutations should work immediately after initialization without manual sequence seeding, just like INSERT operations do.
Additional Context
- Sequence seeding in `db.init()` didn't work (timing issue)
- Lazy seeding before mutations is reliable but feels like a workaround
- Issue affects all TanStack DB PowerSync collections
- Error only happens with WASM workers (manual loading for Turbopack)
Question
Is my workaround correct, or is there a proper way to initialize the ps_crud sequence during PowerSync setup?
Thank you!