tursodatabase/turso · error · Error

getAllRows failed with status: ${bulk.status}

Error message

getAllRows failed with status: ${bulk.status}

What it means

Statement.all() uses the native getAllRows bulk path. DONE returns the rows and IO is drained by calling _statement.runIo() plus the optional _extraIo callback; every other status hits this throw with its numeric code. The value decodes against the TursoStatus enum (4=BUSY, 127=ERROR, 128=MISUSE, 133=CORRUPT, 134=IOERR), and because this is a C++-side row scan, statuses often reflect storage or contention conditions discovered mid-scan.

Source

Thrown at bindings/react-native/src/Statement.ts:316

      for (let ioRetries = 0; ioRetries < MAX_IO_RETRIES; ioRetries++) {
        const bulk = this._statement.getAllRows();
        if (bulk.rows && bulk.rows.length > 0) {
          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 = {};

View on GitHub (pinned to bad083fafb)

Solutions

  1. Decode the numeric status against the TursoStatus enum
  2. Status 4 (BUSY): retry after backoff or avoid concurrent write/read windows
  3. Status 133/134 (CORRUPT/IOERR): verify the database file, let sync re-download pages, check free space
  4. Status 128 (MISUSE): ensure reset()/bind() pairing on reused statements

Example fix

// before
const rows = await stmt.all(); // throws: getAllRows failed with status: 4

// after
async function allWithRetry(stmt, tries = 3) {
  for (let i = 0; ; i++) {
    try { return await stmt.all(); }
    catch (e) {
      const m = /status: (\d+)$/.exec(String(e.message));
      if (i < tries - 1 && m && Number(m[1]) === 4 /* BUSY */) {
        await new Promise(r => setTimeout(r, 50 * (i + 1)));
        continue;
      }
      throw e;
    }
  }
}
Defensive patterns

Strategy: try-catch

Type guard

function isStatusError(e: unknown, status: TursoStatus): boolean {
  return e instanceof Error && e.message.endsWith(`status: ${status}`);
}

Try / catch

try {
  const rows = await stmt.all();
} catch (e) {
  if (isStatusError(e, TursoStatus.BUSY)) {
    await new Promise(r => setTimeout(r, 100));
    return stmt.all(); // bounded retry
  }
  throw e; // CORRUPT/IOERR/MISUSE need investigation, not retry
}

Prevention

When it happens

Trigger: A large SELECT via all() while another connection writes (BUSY 4); scanning pages that are corrupt or hit an IO error mid-bulk-read (133/134); MISUSE (128) when the statement state is invalid entering the bulk read.

Common situations: List screens running big all() queries during background sync writes; reading a partially-synced database whose local pages are incomplete (usually surfaces as IO first, but can degrade to ERROR); storage-level corruption after process kill.

Related errors


AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16). Data as JSON: /api/errors/7261481b2a918227. Report an issue: GitHub.