tursodatabase/turso · error · Error

getAllRows: exceeded ${MAX_IO_RETRIES} IO retries

Error message

getAllRows: exceeded ${MAX_IO_RETRIES} IO retries

What it means

Statement.all()'s bulk-read loop aborts after MAX_IO_RETRIES iterations, which is 1,000,000 (Statement.ts:296). Each iteration that returns TursoStatus.IO calls runIo() and awaits the optional _extraIo() drain, so reaching the cap means the engine kept requesting IO a million times without the read completing — IO that makes no forward progress, effectively an infinite-loop safeguard rather than a legitimate large workload.

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 bad083fafb)

Solutions

  1. Verify the sync URL and auth token are correct and the server actually returns the requested pages (inspect the ioProcessor logs)
  2. Ensure setFileSystemImpl() and the sync IO processor are configured before running queries against a partial-sync database
  3. Check network connectivity before issuing large all() reads and surface offline state in the UI instead of looping
  4. If connectivity is healthy and it still reproduces, capture the HTTP traffic and report it — a healthy drain should complete in a handful of IO cycles

Example fix

// before
const rows = await stmt.all(); // hangs effectively forever, then: exceeded 1000000 IO retries

// after
import NetInfo from '@react-native-community/netinfo';
const net = await NetInfo.fetch();
if (!net.isConnected) throw new Error('offline — cannot complete partial-sync read');
const rows = await stmt.all();
Defensive patterns

Strategy: retry

Validate before calling

import NetInfo from '@react-native-community/netinfo';

async function canReachSyncServer(): Promise<boolean> {
  const net = await NetInfo.fetch();
  return net.isConnected === true && net.isInternetReachable === true;
}
// gate large partial-sync reads:
if (!(await canReachSyncServer())) throw new Error('offline');

Type guard

function isIoRetryLimit(e: unknown): boolean {
  return e instanceof Error && e.message.includes('exceeded') && e.message.includes('IO retries');
}

Try / catch

try {
  return await stmt.all();
} catch (e) {
  if (isIoRetryLimit(e)) {
    // IO made no progress — verify connectivity/config, then retry once later
    await waitOnline();
    return stmt.all();
  }
  throw e;
}

Prevention

When it happens

Trigger: A partial-sync database where every bulk read returns IO and the IO drain never satisfies the request: _extraIo not wired or its fetches returning empty/unusable bodies without throwing; a sync endpoint that accepts requests but never delivers the needed pages; an offline device whose fetches fail silently inside the configured IO processor.

Common situations: Long-lived mobile sessions on flaky networks where the sync engine re-requests the same missing page forever; misconfigured sync URL or auth token causing the server to respond without the requested data; developing against a local sync server that returns 404 bodies that never error.

Related errors


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