n8n-io/n8n · error · LockAcquireTimeoutError
Timeout waiting for lock SqliteWriteConnectionMutex to becom
Error message
Timeout waiting for lock SqliteWriteConnectionMutex to become available
What it means
Thrown by SqliteWriteConnection when its single-writer async-mutex cannot be acquired within the configured acquireTimeout (set from the pool's acquireTimeout option). SQLite permits only one writer at a time; n8n's pooled driver serializes writes behind this mutex. The underlying async-mutex returns the E_TIMEOUT sentinel, which the driver rewrites into LockAcquireTimeoutError and attaches as the cause. The message names the specific lock ('SqliteWriteConnectionMutex').
Source
Thrown at packages/@n8n/typeorm/src/driver/sqlite-pooled/SqliteWriteConnection.ts:186
private assertNotReleased() {
if (this.isReleased) {
throw new DriverAlreadyReleasedError();
}
}
private captureInvariantViolated(extra: Record<string, string | boolean>) {
const error = new InvariantViolatedError();
console.error(
'Invariant violated:',
Object.keys(extra)
.map((key) => `${key}=${extra[key]}`)
.join(', '),
);
console.error(error);
}
private throwLockTimeoutError(cause: Error) {
throw new LockAcquireTimeoutError('SqliteWriteConnectionMutex', {
cause,
});
}
}
View on GitHub (pinned to 5ac6606e81)
Solutions
- Raise the pool acquireTimeout in the datasource config (DB_SQLITE_POOL_ACQUIRE_TIMEOUT or the relevant @n8n/typeorm sqlite pool option) so the longest legitimate write finishes inside the window.
- Find the slow writer: enable DB query logging or DB profiling and look for the write/migration that exceeds the timeout; add missing indexes or batch the operation.
- Ensure only one n8n process uses the SQLite file (SQLite is single-writer by design); move to PostgreSQL for multi-instance or high-write deployments.
- If running on a network/shared filesystem, move the sqlite file to local disk, or switch to Postgres.
- Confirm the write transaction is being committed/released (no leaked runExclusive callbacks, no un-awaited transactions).
Example fix
// before - default timeout too short for large migrations
const ds = new DataSource({
type: 'sqlite',
database: 'n8n.sqlite',
// pool acquireTimeout defaulting to ~5s, large writes time out
});
// after - raise the SQLite pool acquire timeout
const ds = new DataSource({
type: 'sqlite',
database: 'n8n.sqlite',
poolSize: 1,
acquireTimeout: 60_000, // 60s window for the longest write
}); Defensive patterns
Strategy: retry
Validate before calling
// Before issuing the write, confirm no other long writer is in flight
// by checking process state; raise acquireTimeout to a safe bound.
const acquireTimeout = Math.max(
config.DB_SQLITE_POOL_ACQUIRE_TIMEOUT ?? 5_000,
estimatedLongestWriteMs * 2,
);
const ds = new DataSource({ type: 'sqlite', database, acquireTimeout }); Type guard
function isLockAcquireTimeoutError(e: unknown): e is import('@n8n/typeorm/error/LockAcquireTimeoutError').LockAcquireTimeoutError {
return e instanceof Error && /Timeout waiting for lock SqliteWriteConnectionMutex/.test(e.message);
} Try / catch
try {
await writeRepo.save(batch);
} catch (e) {
if (isLockAcquireTimeoutError(e)) {
// transient contention — back off and retry, then surface if still failing
await backoffRetry(() => writeRepo.save(batch), { retries: 3, baseMs: 200 });
return;
}
throw e;
} Prevention
- Run a single n8n/TypeORM process per SQLite file; use Postgres for multi-instance.
- Tune acquireTimeout to at least 2x your slowest legitimate write.
- Keep write transactions short — batch but commit frequently.
- Monitor for slow queries/migrations and index hot tables.
- Move the SQLite file to local disk, not NFS/network shares.
When it happens
Trigger: Calling any write path (INSERT/UPDATE/DELETE, migrations, schema changes) on the SQLite pooled driver while a previous write holds the mutex longer than acquireTimeout. Concretely: a long-running migration, a multi-thousand-row transaction, a query that scans a large table without an index, or a deadlock between an unfinished runExclusive callback and the pool's acquire timeout. Also fires when close() races with an in-flight write and cancel() rejects waiters.
Common situations: Default SQLite deployments of n8n (small/self-hosted) under load spikes; a manual migration on a large database; a workflow that fires many concurrent executions; another process holding the DB file lock (e.g. two n8n instances pointed at the same sqlite file, or an external sqlite3 session in WAL-interactive mode); slow disk/FS (NFS, network volumes) inflating write latency.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Database connection timed out
- Timed out after ${timeoutMs}ms waiting for database connecti
- Task execution timed out after {task_timeout} seconds
- SQLite package has not been found installed. Try to install
- Transactions aren't supported by ${this.connection.driver.op
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/a65fa2d4267c29fc.
Report an issue: GitHub.