tursodatabase/turso · error · Error
getAllRows: exceeded
Error message
getAllRows: exceeded ${MAX_IO_RETRIES} IO retries What it means
Statement.all() on a sync/partial-sync database drives the native getAllRows() in a loop: each time the engine returns TursoStatus.IO it runs the pending IO (fetching missing pages over the network) and retries, capped at MAX_IO_RETRIES = 1000000. This error means the engine requested IO a million times without ever reaching DONE, i.e. the query made no forward progress and the loop was aborted instead of hanging forever.
Solutions
- Check that the device can reach the sync url (auth token valid, network up) - run setup({logLevel: 'debug'}) and inspect the HTTP logs emitted by ioProcessor
- Make the JS package and the native binary come from the same release: after upgrading @tursodatabase/sync-react-native run pod install (iOS) and a clean gradle build (Android)
- Close and re-create the Database connection, then retry the query once - a wedged sync-engine state usually clears on reconnect
- If it reproduces with matched versions and a reachable remote, capture sync logs and file an issue with the query and schema
Example fix
// before - stuck IO loop eventually throws
const rows = await db.all('SELECT * FROM big_table');
// after - bound the wait yourself and reconnect on the guard error
try {
const rows = await db.all('SELECT * FROM big_table');
} catch (e) {
if (e instanceof Error && e.message.startsWith('getAllRows: exceeded')) {
await db.close();
db = await connect(opts); // fresh connection, retry once
return db.all('SELECT * FROM big_table');
}
throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// Before a heavy query on a sync replica, confirm the remote is reachable so the IO loop can actually make progress
export async function assertSyncReachable(db: Database): Promise<void> {
await db.sync(); // cheap round-trip; fails fast with the underlying network error instead of looping
} Try / catch
catch (e) { if (e instanceof Error && e.message.startsWith('getAllRows: exceeded')) { await db.close(); db = await connect(opts); return db.all(sql); } throw e; } Prevention
- Keep the npm package and native binary on the same release so the IO protocol converges
- Run setup({logLevel: 'debug' }) in dev to see every HTTP page fetch that feeds the IO loop
- Wrap long-running all() calls on sync replicas in an application-level timeout so a non-progressing loop never reaches a million retries
When it happens
Trigger: Calling stmt.all() / db.all() on a database opened with a sync url where every getAllRows() call returns IO again: the _extraIo drain (or runIo) is not satisfying the engine's request, e.g. HTTP page fetches that keep failing without poisoning the operation, or a native binary and JS package from different releases whose IO protocol never converges.
Common situations: Sync replica whose remote is unreachable or returning bad frames while the sync engine keeps re-requesting the same pages; upgrading only the npm package without rebuilding the native side (pod install / gradle); effectively an infinite IO loop that this guard converts into an error.
Related errors
- checkpoint() is only available for sync databases
- getAllRows failed with status
- has_hole is not supported for the given IO implementation
- HTTP request failed: . URL: , Method: , Body size: bytes
- HTTP request missing URL: no URL in request and no baseUrl…
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/1586e93c9c2e1f7b.
Report an issue: GitHub.
Appendix: source
Thrown at bindings/react-native/src/Statement.ts:319
rows = rows.concat(bulk.rows);
}
if (bulk.status === TursoStatus.DONE) {
return rows;
}
if (bulk.status === TursoStatus.IO) {
this._statement.runIo();
if (this._extraIo) {
await this._extraIo();
}
continue;
}
throw new Error(`getAllRows failed with status: ${bulk.status}`);
}
throw new Error(`getAllRows: exceeded ${MAX_IO_RETRIES} IO retries`);
} finally {
this._statement.reset();
if (this._execLock) {
this._execLock.release();
}
}
}
/**
* Read current row into an object
*
* @returns Row object with column name keys
*/
private readRow(): Row {
const row: Row = {};
const columnCount = this._statement.columnCount();
for (let i = 0; i < columnCount; i++) {View on GitHub (pinned to 244cde92a7)