tursodatabase/turso · error · Error
No active remote transaction
Error message
No active remote transaction
What it means
RemoteWriter.commitTransaction() (bindings/javascript/sync/packages/common/remote-writer.ts:90) sends COMMIT on the current session and throws when this.session is null - i.e. no BEGIN was executed (or the previous transaction already tore the session down in its finally block, which sets session = null). The writer models one session per remote transaction, so committing without a matching beginTransaction() is an invalid-state error.
Solutions
- Check writer.isInTransaction (or session presence) before committing and skip when false.
- Ensure every commitTransaction is paired with a successful beginTransaction on the same writer instance.
- Make cleanup idempotent: after rollback/commit in a finally, clear your own 'txn open' flag so later handlers do not commit again.
- If BEGIN failed, do not run the COMMIT branch of your transaction wrapper.
Example fix
// before
await writer.commitTransaction(); // no beginTransaction before it
// after
if (writer.isInTransaction) {
await writer.commitTransaction();
} Defensive patterns
Strategy: validation
Validate before calling
if (writer.isInRemoteTxn) {
await writer.commitTransaction();
} Type guard
const hasRemoteTransaction = (w: { isInTransaction: boolean }): boolean => w.isInTransaction; Try / catch
try {
await writer.commitTransaction();
} catch (e) {
if (e instanceof Error && e.message === "No active remote transaction") {
// nothing to commit: treat as already-closed and continue
} else throw e;
} Prevention
- Pair every commit with a successful beginTransaction on the same writer.
- Check isInTransaction before terminal operations.
- Make transaction cleanup idempotent with a settled flag.
When it happens
Trigger: Calling commitTransaction() without a prior beginTransaction(mode); calling commit twice (the second finds session null after the first's finally reset); an error path that already closed the session (commit/rollback both null it in finally) followed by a cleanup routine that commits again; a state machine replaying COMMIT after a rollback.
Common situations: Sync-engine integrations where local transaction state and remote writer state drift (local COMMIT reaches the writer but the remote BEGIN was filtered or failed); error handlers that 'commit if not rolled back' racing with an earlier rollback; reusing one RemoteWriter across sequential transactions without re-beginning.
Related errors
- NOT_SUPPORTED
- The transaction has already completed
- transactionAsync is not supported with…
- transactionAsync is not supported with…
- transactionAsync is not supported with…
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/6ca581a10a14fc15.
Report an issue: GitHub.
Appendix: source
Thrown at bindings/javascript/sync/packages/common/remote-writer.ts:90
await session.close();
}
}
/**
* Begin a remote transaction. Creates a session and sends BEGIN.
*/
async beginTransaction(mode: string): Promise<void> {
this.session = await this.createSession();
await this.session.sequence("BEGIN " + mode);
this._inRemoteTxn = true;
}
/**
* Commit the remote transaction. Sends COMMIT and closes the session.
*/
async commitTransaction(): Promise<void> {
if (!this.session) {
throw new Error("No active remote transaction");
}
try {
await this.session.sequence("COMMIT");
} finally {
this._inRemoteTxn = false;
await this.session.close();
this.session = null;
}
}
/**
* Rollback the remote transaction. Sends ROLLBACK and closes the session.
*/
async rollbackTransaction(): Promise<void> {
if (!this.session) {
throw new Error("No active remote transaction");
}
try {View on GitHub (pinned to 244cde92a7)