tursodatabase/turso · error
transactionAsync is not supported with…
Error message
transactionAsync is not supported with remoteWritesExperimental yet; use the deprecated transaction() for now
What it means
transactionAsync hands the callback a Transaction handle bound to a local connection that is owned for the whole BEGIN..COMMIT window. When the database was constructed with remoteWritesExperimental, transactions execute on the remote server and there is no local connection to hand out, so the override throws rather than silently misbehave. The message points you to the deprecated transaction(), whose remote path wraps the entire callback in a remote BEGIN..COMMIT.
Solutions
- Replace transactionAsync(fn) with transaction(fn); the remote writer wraps the whole callback remotely
- Inside the callback, use the database handle (db.exec) instead of the per-connection txn handle
- If you need the local Transaction handle, disable remoteWritesExperimental in DatabaseOpts
- Centralize transaction creation in one adapter so the mode switch is a single code path
Example fix
// before
const run = db.transactionAsync(async (txn) => {
await txn.exec("INSERT INTO orders ...");
});
await run();
// after (remoteWritesExperimental enabled)
const run = db.transaction(async () => {
await db.exec("INSERT INTO orders ...");
});
await run(); Defensive patterns
Strategy: validation
Validate before calling
// Route at construction time: remoteWritesExperimental forbids transactionAsync const remoteWrites = Boolean(opts.remoteWritesExperimental && opts.url); const run = remoteWrites ? db.transaction(fn) // remote BEGIN..COMMIT wrapper : db.transactionAsync(fn); // local connection handle await run();
Try / catch
try {
const run = db.transactionAsync(fn);
await run();
} catch (err) {
if (err instanceof Error && err.message.includes("remoteWritesExperimental")) {
// fall back to the supported API
await db.transaction(fn)();
} else {
throw err;
}
} Prevention
- Decide the transaction API once, based on the remoteWritesExperimental option, and use it everywhere
- Do not copy transactionAsync call sites into remote-writes-enabled codebases
- Wrap transaction creation in a single adapter so a mode switch cannot leave mixed call sites
When it happens
Trigger: new Database({ url, authToken, remoteWritesExperimental: true }) followed by db.transactionAsync((txn) => ...) — the remoteWriter being present is exactly what triggers the throw.
Common situations: Copying transactionAsync-based helpers from a local-connection codebase into a remoteWrites-enabled app; enabling the experimental flag during a migration and reusing existing transaction utilities; version upgrades where remoteWritesExperimental was newly introduced.
Related errors
- transactionAsync is not supported with…
- transactionAsync is not supported with…
- checkpoint() is only available for sync databases
- Expected first argument to be a function
- Expected first argument to be a function
AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-08-20).
Data as JSON: /api/errors/309f6a1a6653576d.
Report an issue: GitHub.
Appendix: source
Thrown at bindings/javascript/sync/packages/wasm/promise-default.ts:328
Object.defineProperties(properties.immediate.value, properties);
Object.defineProperties(properties.exclusive.value, properties);
return properties.default.value as TransactionFunction<F>;
}
/**
* Returns a function that executes the given function in a transaction
* on a connection owned for the whole BEGIN..COMMIT window; the callback
* receives a {@link Transaction} handle as its first argument.
*
* Not supported together with {@link DatabaseOpts.remoteWritesExperimental}
* yet: remote-writes transactions run on the remote server and have no
* local connection to hand out.
*/
override transactionAsync<F extends (txn: Transaction, ...args: any[]) => Promise<any>>(
fn: F,
): AsyncTransactionFunction<F> {
if (this.#remoteWriter) {
throw new Error(
"transactionAsync is not supported with remoteWritesExperimental yet; use the deprecated transaction() for now",
);
}
return super.transactionAsync(fn);
}
/**
* close the database and relevant files
*/
async close() {
if (this.#remoteWriter) {
await this.#remoteWriter.close();
}
if (this.#engine != null) {
if (this.name != null && this.#worker != null) {
const worker = this.#worker;
await Promise.all(this.#engine.filePaths().map((path: string) => unregisterFileAtWorker(worker, path)));
}View on GitHub (pinned to 6c72522679)