tursodatabase/turso · error · Error

pull() is only available for sync databases

Error message

pull() is only available for sync databases

What it means

pull() waits for remote changes via the native sync engine (waitChanges) and applies them, which only exists for sync databases. The guard requires _isSync, _nativeSyncDb, and _ioContext — all created during connect() when the Database was constructed with a `url`. A local-only database has no sync engine, so pull is meaningless and rejected up front.

Solutions

  1. Pass url and authToken in the Database options so isSyncConfig() selects the sync path
  2. Always `await db.connect()` before pull() — it bootstraps the replica and creates the sync handle
  3. Gate sync calls: `if (db.isSync) await db.pull();` in code paths shared with local-only builds
  4. Verify a url function option actually returns a string, not null

Example fix

// before
const db = new Database({ path: getDbPath('notes.db') });
await db.connect();
await db.pull(); // throws

// after
const db = new Database({
  path: getDbPath('notes.db'),
  url: () => remoteUrl, // string or function returning string
  authToken,
});
await db.connect();
if (db.isSync) {
  await db.pull();
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!db.isSync) {
  return; // local-only build: nothing to pull
}
await db.pull();

Type guard

function canPull(db: Database): boolean {
  return db.isSync && db.open;
}

Try / catch

try {
  const changed = await db.pull();
} catch (e) {
  if (e instanceof Error && e.message.includes('only available for sync databases')) {
    return; // configuration mismatch — skip sync on local-only instances
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling await db.pull() on a Database constructed without `url`; calling it on a sync database before `await db.connect()` finished creating the native sync handle and IO context; the url option resolving to null at construction time (url function returning null).

Common situations: Feature-flagged sync where some builds construct the db local-only but shared code still calls pull(); forgetting to await connect() before an initial pull; copying example code for pull() into the local-only quick-start snippet from the README.

Related errors


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/e3b2d6c2a1416065. Report an issue: GitHub.

Appendix: source

Thrown at bindings/react-native/src/Database.ts:362

   * Push local changes to remote (sync databases only)
   */
  async push(): Promise<void> {
    if (!this._isSync || !this._nativeSyncDb || !this._ioContext) {
      throw new Error('push() is only available for sync databases');
    }

    const operation = this._nativeSyncDb.pushChanges();
    await driveVoidOperation(operation, this._nativeSyncDb, this._ioContext);
  }

  /**
   * Pull remote changes and apply locally (sync databases only)
   *
   * @returns true if changes were applied, false if no changes
   */
  async pull(): Promise<boolean> {
    if (!this._isSync || !this._nativeSyncDb || !this._ioContext) {
      throw new Error('pull() is only available for sync databases');
    }

    // Wait for changes
    const waitOperation = this._nativeSyncDb.waitChanges();
    const changes = await driveChangesOperation(waitOperation, this._nativeSyncDb, this._ioContext);

    // If no changes, return false
    if (!changes) {
      return false;
    }

    // Apply changes
    const applyOperation = this._nativeSyncDb.applyChanges(changes);
    await driveVoidOperation(applyOperation, this._nativeSyncDb, this._ioContext);

    return true;
  }

View on GitHub (pinned to 244cde92a7)