tursodatabase/turso · error · Error

push() is only available for sync databases

Error message

push() is only available for sync databases

What it means

push() on the React Native Database uploads local changes through the native sync database object. The guard requires three things that only exist on a connected sync database: _isSync (set in the constructor when opts.url is non-null), _nativeSyncDb, and _ioContext (both created during connect() in sync mode). If the database is local-only, or sync mode was configured but connect() has not completed, the call throws.

Source

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

  async transaction<T>(fn: () => T | Promise<T>): Promise<T> {
    this.checkOpen();
    await this.exec('BEGIN');
    try {
      const result = await fn();
      await this.exec('COMMIT');
      return result;
    } catch (error) {
      await this.exec('ROLLBACK');
      throw error;
    }
  }

  /**
   * 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();

View on GitHub (pinned to bad083fafb)

Solutions

  1. Pass `url` (and `authToken`) to the Database constructor so it is created in sync mode
  2. Always `await db.connect()` before any push/pull/stats/checkpoint call
  3. Guard the call site: keep a typed 'synced database' wrapper so push() is unreachable for local handles

Example fix

// before
const db = new Database({ path: 'app.db' }); // no url -> local mode
await db.push(); // throws

// after
const db = new Database({ path: 'app.db', url, authToken });
await db.connect();
await db.push();
Defensive patterns

Strategy: validation

Validate before calling

// Mode is decided by url presence in the constructor opts — check it, and gate on connect()
function isSyncConfig(opts: DatabaseOpts): boolean {
  return opts.url !== undefined && opts.url !== null;
}

if (isSyncConfig(opts)) {
  await db.connect(); // creates _nativeSyncDb + _ioContext
  await db.push();
}

Try / catch

try { await db.push(); } catch (e) { if (e instanceof Error && e.message.includes('only available for sync databases')) { /* wrong mode or not connected: fix config/lifecycle */ } throw e; }

Prevention

When it happens

Trigger: `new Database({ path: 'app.db' })` with no url followed by `await db.push()`; constructing with url but calling push() before `await db.connect()` finishes; a sync-call helper invoked on a database whose connect() failed earlier (leaving _nativeSyncDb null).

Common situations: Adding sync calls to an app first built as local-only; race conditions at app startup where sync runs before connect resolves; code shared between local and synced screens; error paths where connect() threw and later code still attempts to push.

Related errors


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