tursodatabase/turso · error · LibsqlError

NOT_SUPPORTED

NOT_SUPPORTED

Error message

Sync not supported for remote databases

What it means

sync() on the compatibility-layer client always throws a LibsqlError with code NOT_SUPPORTED and the message 'Sync not supported for remote databases'. The compat layer talks to the database over the SQL-over-HTTP protocol against a remote Turso endpoint; embedded-replica sync (pulling a local copy from a sync server) is a local-file client feature that has no equivalent here, so the method exists only to keep API shape parity and rejects unconditionally.

Source

Thrown at serverless/javascript/src/compat.ts:506

    await this.execLock.acquire();
    try {
      if (this._closed) {
        throw new LibsqlError("Client is closed", "CLIENT_CLOSED");
      }

      await this.session.sequence(sql);
    } catch (error: any) {
      if (error instanceof LibsqlError) {
        throw error;
      }
      throw mapDatabaseError(error, "EXECUTE_MULTIPLE_ERROR");
    } finally {
      this.execLock.release();
    }
  }

  async sync(): Promise<any> {
    throw new LibsqlError("Sync not supported for remote databases", "NOT_SUPPORTED");
  }

  close(): void {
    this._closed = true;
    // Note: The libSQL client interface expects synchronous close,
    // but our underlying session needs async close. We'll fire and forget.
    this.session.close().catch(error => {
      console.error('Error closing session:', error);
    });
  }
}

/**
 * Create a libSQL-compatible client for Turso database access.
 * 
 * This function provides compatibility with the standard libSQL client API
 * while using the Turso serverless driver under the hood.
 * 

View on GitHub (pinned to bad083fafb)

Solutions

  1. Remove sync() calls — a pure remote client is always current; there is nothing to synchronize
  2. If you need embedded replicas, use a client that supports them (e.g. @libsql/client with a local file: URL) outside serverless runtimes
  3. Branch your data layer on whether sync is available instead of calling it unconditionally
  4. Delete syncUrl/syncInterval config — they are deprecated and rejected by this layer's option validation

Example fix

// before
const client = createClient({ url: process.env.TURSO_URL! });
await client.sync(); // NOT_SUPPORTED

// after
const client = createClient({ url: process.env.TURSO_URL! });
// remote client is always current — no sync call needed
Defensive patterns

Strategy: fallback

Validate before calling

// This client never supports sync(); branch before calling it.
const supportsSync = false; // remote serverless client
if (supportsSync) {
  await client.sync();
} else {
  // remote client is always current — nothing to do
}

Type guard

type SyncCapable = { sync(): Promise<unknown> };
const canSync = (c: unknown): c is SyncCapable =>
  typeof (c as SyncCapable)?.sync === 'function' && !('protocol' in c && (c as any).protocol === 'http');

Try / catch

try {
  await client.sync();
} catch (e) {
  if (e instanceof LibsqlError && e.code === 'NOT_SUPPORTED') {
    // Expected on the remote serverless client — skip sync silently
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Porting @libsql/client code that used a local file URL with syncUrl/syncInterval and calling await client.sync() against the serverless client. Generic wrapper code that calls sync() on any client it is handed. Feature-detecting by calling sync() inside try/catch.

Common situations: Migrating an app from embedded replicas (libsql local file + sync) to pure remote access in serverless/edge runtimes; shared data-layer code that must now branch between local and remote clients.

Related errors


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