{"record":{"id":"49a6de3e737ef595","repo":"tursodatabase/turso","slug":"sync-is-disabled-as-database-was-opened-without-sy-49a6de","errorCode":null,"errorMessage":"sync is disabled as database was opened without sync support","messagePattern":"sync is disabled as database was opened without sync support","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"bindings/javascript/sync/packages/wasm/promise-vite-dev-hack.ts","lineNumber":194,"sourceCode":"                    registerFileAtWorker(this.#worker, this.name),\n                    registerFileAtWorker(this.#worker, `${this.name}-wal`),\n                    registerFileAtWorker(this.#worker, `${this.name}-wal-revert`),\n                    registerFileAtWorker(this.#worker, `${this.name}-info`),\n                    registerFileAtWorker(this.#worker, `${this.name}-changes`),\n                ]);\n            }\n            await run(this.#runner, this.#engine.connect(), this.execLock);\n        }\n        this.connected = true;\n    }\n    /**\n     * pull new changes from the remote database\n     * 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.\n     * @returns true if new changes were pulled from the remote\n     */\n    async pull() {\n        if (this.#engine == null) {\n            throw new Error(\"sync is disabled as database was opened without sync support\")\n        }\n        const changes = await this.#guards.wait(async () => await run(this.#runner, this.#engine.wait(), this.execLock));\n        if (changes.empty()) {\n            return false;\n        }\n        await this.#guards.apply(async () => await run(this.#runner, this.#engine.apply(changes), this.execLock));\n        return true;\n    }\n    /**\n     * push new local changes to the remote database\n     * if {@link DatabaseOpts.transform} is set - then provided callback will be called for every mutation before sending it to the remote\n     */\n    async push() {\n        if (this.#engine == null) {\n            throw new Error(\"sync is disabled as database was opened without sync support\")\n        }\n        await this.#guards.push(async () => await run(this.#runner, this.#engine.push(), this.execLock));\n    }","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/javascript/sync/packages/wasm/promise-vite-dev-hack.ts#L176-L212","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst db = new Database(\"app.db\"); // no url -> engine is null\nawait db.pull(); // throws\n\n// after\nconst db = new Database(\"app.db\", { url: \"https://your-db.turso.io\", authToken: token });\nawait db.connect();\nawait db.pull();","handlingStrategy":"validation","validationCode":"// Mirror the constructor's own decision: engine exists iff url is non-null\nfunction isSyncEnabled(opts: DatabaseOpts): boolean {\n  return typeof opts.url === 'function' ? opts.url() != null : opts.url != null;\n}\n\nif (isSyncEnabled(opts)) {\n  await db.pull();\n} else {\n  // local-only: skip sync lifecycle entirely\n}","typeGuard":null,"tryCatchPattern":"try { await db.pull(); } catch (e) { if (e instanceof Error && e.message.includes('sync is disabled')) { /* local-only instance: skip */ } else throw e; }","preventionTips":["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"],"tags":["sync","pull","configuration","wasm","vite"],"backgroundTag":"feature-not-enabled","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}