tursodatabase/turso · error · Error
Statement execution failed with status
Error message
Statement execution failed with status: ${result.status} What it means
executeWithIo() loops calling runStep: a status of TursoStatus.IO means the statement needs IO (partial-sync page fetch), which the loop services via runIo() + draining the sync engine; DONE means success. Any other non-IO, non-DONE status reaching the check is a native execution failure, surfaced with its numeric status code.
Solutions
- Log result.status together with the SQL and parameters; the numeric code identifies the native failure
- Rebuild the app so the JS layer and the C++/native library are from the same package version (mismatched upgrades are a common source)
- Reduce to a minimal reproduction (same SQL via db.exec) and report it with the status code to the Turso repo
- Retry once on a fresh connection after closing and reopening the database to rule out transient connection state
Example fix
// before
const result = await stmt.run(params); // may throw opaque status error
// after: capture status context for diagnosis
try {
const result = await stmt.run(params);
} catch (e) {
reportError(e, { sql: stmtSql, params }); // message contains the status code
throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// No pre-check exists for native status codes; validate cheap health first
await db.get('SELECT 1'); // probe connection before critical writes
const result = await stmt.run(params); Try / catch
try {
await stmt.run(params);
} catch (e) {
if (e instanceof Error && /failed with status/.test(e.message)) {
// one recovery attempt on a fresh connection, then surface with context
await resetDatabaseConnection();
return db.prepare(sql).run(params);
}
throw e;
} Prevention
- Keep JS package and native binary versions in lockstep and rebuild on every upgrade
- Log SQL + status code whenever this fires — the numeric status is the diagnosis entry point
- Probe with 'SELECT 1' before critical write batches to separate connection-wide from statement-specific failures
When it happens
Trigger: A run() whose native execution returns an unexpected status (e.g. an error/busy/invalid state code from the C engine) after IO retries; statements executed against a connection invalidated by an error earlier; internal errors in the native layer while running INSERT/UPDATE/DELETE.
Common situations: Rare in practice — this wraps native status codes that escape normal handling. When it appears, capture result.status and the SQL: it usually accompanies a native-level failure (corrupt state, unsupported operation, or a binding/native version mismatch after a partial upgrade).
Related errors
- getAllRows failed with status
- Statement step failed with status
- Statement has been finalized
- Unknown parameter name
- Unsupported parameter type
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/9bf65606e9124363.
Report an issue: GitHub.
Appendix: source
Thrown at bindings/react-native/src/Statement.ts:199
*/
private async executeWithIo(): Promise<{ status: number; rowsChanged: number }> {
while (true) {
const result = this._statement.execute();
if (result.status === TursoStatus.IO) {
// Statement needs IO (e.g., loading missing pages with partial sync)
this._statement.runIo();
// Drain sync engine IO queue
if (this._extraIo) {
await this._extraIo();
}
continue;
}
if (result.status !== TursoStatus.DONE) {
throw new Error(`Statement execution failed with status: ${result.status}`);
}
return result;
}
}
/**
* Step statement once handling potential IO (for partial sync)
* Matches Python's _step_once_with_io pattern
*
* @returns Status code
*/
private async stepWithIo(): Promise<number> {
while (true) {
const status = this._statement.step();
if (status === TursoStatus.IO) {
// Statement needs IO (e.g., loading missing pages with partial sync)View on GitHub (pinned to 244cde92a7)