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

  1. Log result.status together with the SQL and parameters; the numeric code identifies the native failure
  2. Rebuild the app so the JS layer and the C++/native library are from the same package version (mismatched upgrades are a common source)
  3. Reduce to a minimal reproduction (same SQL via db.exec) and report it with the status code to the Turso repo
  4. 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

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


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)