tursodatabase/turso · error · Error

sync is disabled as database was opened without sync support

Error message

sync is disabled as database was opened without sync support

What it means

pull() fetches remote changes through a SyncEngine, but the engine is only created in the constructor when opts.url is non-null — the source shows `if (opts.url == null) { ... this.#engine = null; return; }`. When the database is opened as local-only, #engine stays null and every sync operation, including pull(), throws this error. It signals a construction-time configuration gap, not a network failure.

Source

Thrown at bindings/javascript/sync/packages/wasm/promise-vite-dev-hack.ts:194

                    registerFileAtWorker(this.#worker, this.name),
                    registerFileAtWorker(this.#worker, `${this.name}-wal`),
                    registerFileAtWorker(this.#worker, `${this.name}-wal-revert`),
                    registerFileAtWorker(this.#worker, `${this.name}-info`),
                    registerFileAtWorker(this.#worker, `${this.name}-changes`),
                ]);
            }
            await run(this.#runner, this.#engine.connect(), this.execLock);
        }
        this.connected = true;
    }
    /**
     * pull new changes from the remote database
     * if {@link DatabaseOpts.longPollTimeoutMs} is set - then server will hold the connection open until either new changes will appear in the database or timeout occurs.
     * @returns true if new changes were pulled from the remote
     */
    async pull() {
        if (this.#engine == null) {
            throw new Error("sync is disabled as database was opened without sync support")
        }
        const changes = await this.#guards.wait(async () => await run(this.#runner, this.#engine.wait(), this.execLock));
        if (changes.empty()) {
            return false;
        }
        await this.#guards.apply(async () => await run(this.#runner, this.#engine.apply(changes), this.execLock));
        return true;
    }
    /**
     * push new local changes to the remote database
     * if {@link DatabaseOpts.transform} is set - then provided callback will be called for every mutation before sending it to the remote
     */
    async push() {
        if (this.#engine == null) {
            throw new Error("sync is disabled as database was opened without sync support")
        }
        await this.#guards.push(async () => await run(this.#runner, this.#engine.push(), this.execLock));
    }

View on GitHub (pinned to bad083fafb)

Solutions

  1. Open the database with sync support: pass both `url` and `authToken` in DatabaseOpts so the constructor builds the SyncEngine
  2. If the database must stay local-only, remove the pull() call from that code path
  3. Keep two clearly-typed handles (local vs synced) so sync operations are only reachable on the synced one

Example fix

// before
const db = new Database("app.db"); // no url -> engine is null
await db.pull(); // throws

// after
const db = new Database("app.db", { url: "https://your-db.turso.io", authToken: token });
await db.connect();
await db.pull();
Defensive patterns

Strategy: validation

Validate before calling

// Mirror the constructor's own decision: engine exists iff url is non-null
function isSyncEnabled(opts: DatabaseOpts): boolean {
  return typeof opts.url === 'function' ? opts.url() != null : opts.url != null;
}

if (isSyncEnabled(opts)) {
  await db.pull();
} else {
  // local-only: skip sync lifecycle entirely
}

Try / catch

try { await db.pull(); } catch (e) { if (e instanceof Error && e.message.includes('sync is disabled')) { /* local-only instance: skip */ } else throw e; }

Prevention

When it happens

Trigger: Opening with `new Database("local.db")` (no url option) and then calling `await db.pull()`; using the same wrapper class for a local cache database and a synced database and calling pull() on the wrong instance.

Common situations: Starting a project local-only and adding sync calls before adding sync config; helper code that calls pull/push on every database handle regardless of mode; tests that construct databases without url but exercise sync paths; forgetting authToken alone does not cause this — only a missing/null url does.

Related errors


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