n8n-io/n8n · error · TransactionRollbackFailedError
Transaction rollback failed
Error message
Transaction rollback failed
What it means
Thrown by the pooled SQLite read/write runner when the `ROLLBACK` SQL statement itself fails inside rollbackTransaction(). The original error is passed as `error.cause` (see TransactionRollbackFailedError). The runner marks the leased connection invalid and releases the lease in a finally block — so the transaction is terminated but the connection must not be reused.
Source
Thrown at packages/@n8n/typeorm/src/driver/sqlite-pooled/SqliteReadWriteQueryRunner.ts:149
}
/**
* Rollbacks transaction.
* Error will be thrown if transaction was not started.
*/
async rollbackTransaction(): Promise<void> {
if (!this.isTransactionActive) throw new TransactionNotStartedError();
if (!this.trxDbLease) throw new TransactionNotStartedError();
try {
await this.broadcaster.broadcast('BeforeTransactionRollback');
await this.runQueryWithinConnection(this.trxDbLease.connection, 'ROLLBACK');
await this.broadcaster.broadcast('AfterTransactionRollback');
} catch (rollbackError) {
this.trxDbLease.markAsInvalid();
throw new TransactionRollbackFailedError(rollbackError);
} finally {
this.releaseTrxDbLease();
}
}
/**
* Executes a given SQL query.
*/
async query(query: string, parameters?: unknown[], useStructuredResult = false): Promise<any> {
if (!this.connection.isInitialized) {
throw new ConnectionIsNotSetError('sqlite');
}
if (this.trxDbLease) {
return await this.runQueryWithinConnection(
this.trxDbLease.connection,
query,
parameters,View on GitHub (pinned to 5ac6606e81)
Solutions
- Inspect `error.cause` for the real SQLite code/message and address that root cause.
- Keep the DB file on stable local storage for the process lifetime.
- Fix the offending statement that left the transaction in a bad state.
- Re-open the DataSource / restart the process — the lease is released and marked invalid; do not reuse the runner.
Example fix
// before
await queryRunner.rollbackTransaction();
// after
try {
await queryRunner.rollbackTransaction();
} catch (e) {
if (e instanceof TransactionRollbackFailedError) {
logger.error('rollback failed', { cause: e.cause });
await dataSource.destroy(); // connection is unusable
}
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// No safe pre-check: rollback fails at the SQL layer.
// Keep the connection healthy:
if (!queryRunner.connection.isInitialized) {
throw new Error('DataSource not initialized — cannot rollback');
} Type guard
import { TypeORMError } from '@n8n/typeorm';
function isTransactionRollbackFailedError(e: unknown): e is TypeORMError & { cause: unknown } {
return e instanceof TypeORMError && e.message === 'Transaction rollback failed';
} Try / catch
try {
await queryRunner.rollbackTransaction();
} catch (e) {
if (isTransactionRollbackFailedError(e)) {
logger.error('sqlite rollback failed', { cause: e.cause });
await dataSource.destroy().catch(() => {});
}
throw e;
} Prevention
- Keep the SQLite file on local, stable storage.
- Avoid long-running transactions that increase exposure to I/O or lock failures.
- Fix statements that leave the transaction in a bad state.
- Log error.cause — the real SQLite code is the actionable signal.
When it happens
Trigger: Calling rollbackTransaction() on a SqliteReadWriteQueryRunner when the ROLLBACK hits SQLITE_IOERR, the DB file became unreachable, or the connection lease was already invalidated by a prior statement error.
Common situations: SQLite DB file on an unreliable mount, disk full, file deleted while running, concurrent write-lock corruption, or a prior statement that broke transaction state.
Related errors
- Transaction rollback failed
- Transaction commit failed
- SQLite package has not been found installed. Try to install
- Transactions aren't supported by ${this.connection.driver.op
- SQLite only supports SERIALIZABLE and READ UNCOMMITTED isola
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/4d0185ecc6da4a52.
Report an issue: GitHub.