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
- Open the database with sync support: pass both `url` and `authToken` in DatabaseOpts so the constructor builds the SyncEngine
- If the database must stay local-only, remove the pull() call from that code path
- 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
- Keep exactly one database factory in the app that records whether sync was enabled
- Never write generic 'syncAll(dbs)' helpers that assume every handle is synced
- Constructing with url is the only way to get an engine — it cannot be attached later
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
- sync is disabled as database was opened without sync support
- remoteWritesExperimental requires a non-null URL
- sync is disabled as database was opened without sync support
- remoteWritesExperimental requires a non-null URL
- sync is disabled as database was opened without sync support
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/49a6de3e737ef595.
Report an issue: GitHub.