{"record":{"id":"1586e93c9c2e1f7b","repo":"tursodatabase/turso","slug":"getallrows-exceeded-max-io-retries-io-retries","errorCode":null,"errorMessage":"getAllRows: exceeded ${MAX_IO_RETRIES} IO retries","messagePattern":"getAllRows: exceeded (.+?) IO retries","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"bindings/react-native/src/Statement.ts","lineNumber":319,"sourceCode":"          rows = rows.concat(bulk.rows);\n        }\n\n        if (bulk.status === TursoStatus.DONE) {\n          return rows;\n        }\n\n        if (bulk.status === TursoStatus.IO) {\n          this._statement.runIo();\n          if (this._extraIo) {\n            await this._extraIo();\n          }\n          continue;\n        }\n\n        throw new Error(`getAllRows failed with status: ${bulk.status}`);\n      }\n\n      throw new Error(`getAllRows: exceeded ${MAX_IO_RETRIES} IO retries`);\n    } finally {\n      this._statement.reset();\n      if (this._execLock) {\n        this._execLock.release();\n      }\n    }\n  }\n\n  /**\n   * Read current row into an object\n   *\n   * @returns Row object with column name keys\n   */\n  private readRow(): Row {\n    const row: Row = {};\n    const columnCount = this._statement.columnCount();\n\n    for (let i = 0; i < columnCount; i++) {","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/tursodatabase/turso/blob/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/react-native/src/Statement.ts#L301-L337","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before - stuck IO loop eventually throws\nconst rows = await db.all('SELECT * FROM big_table');\n\n// after - bound the wait yourself and reconnect on the guard error\ntry {\n  const rows = await db.all('SELECT * FROM big_table');\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('getAllRows: exceeded')) {\n    await db.close();\n    db = await connect(opts); // fresh connection, retry once\n    return db.all('SELECT * FROM big_table');\n  }\n  throw e;\n}","handlingStrategy":"retry","validationCode":"// Before a heavy query on a sync replica, confirm the remote is reachable so the IO loop can actually make progress\nexport async function assertSyncReachable(db: Database): Promise<void> {\n  await db.sync(); // cheap round-trip; fails fast with the underlying network error instead of looping\n}","typeGuard":null,"tryCatchPattern":"catch (e) { if (e instanceof Error && e.message.startsWith('getAllRows: exceeded')) { await db.close(); db = await connect(opts); return db.all(sql); } throw e; }","preventionTips":["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"],"tags":["react-native","sync","io","partial-sync","infinite-loop"],"backgroundTag":"io-retry-limit-exceeded","analyzedSha":"244cde92a7df7f9b8b8b7a4075c35a12977e303e","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}