{"record":{"id":"21d33d7e65b28371","repo":"n8n-io/n8n","slug":"sqlite-only-supports-serializable-and-read-uncommi","errorCode":null,"errorMessage":"SQLite only supports SERIALIZABLE and READ UNCOMMITTED isolation","messagePattern":"SQLite only supports SERIALIZABLE and READ UNCOMMITTED isolation","errorType":"exception","errorClass":"TypeORMError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/typeorm/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts","lineNumber":86,"sourceCode":"\n\t/**\n\t * Starts transaction.\n\t */\n\tasync startTransaction(isolationLevel?: IsolationLevel): Promise<void> {\n\t\tif (this.driver.transactionSupport === 'none')\n\t\t\tthrow new TypeORMError(\n\t\t\t\t`Transactions aren't supported by ${this.connection.driver.options.type}.`,\n\t\t\t);\n\n\t\tif (this.isTransactionActive && this.driver.transactionSupport === 'simple')\n\t\t\tthrow new TransactionAlreadyStartedError();\n\n\t\tif (\n\t\t\tisolationLevel &&\n\t\t\tisolationLevel !== 'READ UNCOMMITTED' &&\n\t\t\tisolationLevel !== 'SERIALIZABLE'\n\t\t)\n\t\t\tthrow new TypeORMError(`SQLite only supports SERIALIZABLE and READ UNCOMMITTED isolation`);\n\n\t\tthis.isTransactionActive = true;\n\t\ttry {\n\t\t\tawait this.broadcaster.broadcast('BeforeTransactionStart');\n\t\t} catch (err) {\n\t\t\tthis.isTransactionActive = false;\n\t\t\tthrow err;\n\t\t}\n\n\t\tif (this.transactionDepth === 0) {\n\t\t\tthis.transactionDepth += 1;\n\t\t\tif (isolationLevel) {\n\t\t\t\tif (isolationLevel === 'READ UNCOMMITTED') {\n\t\t\t\t\tawait this.query('PRAGMA read_uncommitted = true');\n\t\t\t\t} else {\n\t\t\t\t\tawait this.query('PRAGMA read_uncommitted = false');\n\t\t\t\t}\n\t\t\t}","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/typeorm/src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts#L68-L104","documentation":"TypeORMError('SQLite only supports SERIALIZABLE and READ UNCOMMITTED isolation') is raised in startTransaction when an isolationLevel is requested that is neither 'READ UNCOMMITTED' nor 'SERIALIZABLE'. SQLite's isolation model only exposes these two levels, so requesting READ COMMITTED or REPEATABLE READ is rejected.","triggerScenarios":"Caller invokes startTransaction('READ COMMITTED') or startTransaction('REPEATABLE READ') against a sqlite-family driver. The guard fires before any SQL is issued.","commonSituations":"Code written for postgres (which accepts the full isolation ladder) is reused against sqlite; a generic helper passes a default isolation level without driver-awareness; tests run against sqlite but production uses postgres.","solutions":["Pass undefined (no isolation level) or one of 'READ UNCOMMITTED' / 'SERIALIZABLE' when running against sqlite.","Make the isolation level configurable per-environment and omit it for sqlite.","Use postgres for environments that genuinely need READ COMMITTED / REPEATABLE READ semantics.","Guard the call: check the driver type before requesting a level."],"exampleFix":"// before\nawait qr.startTransaction('READ COMMITTED');  // fails on sqlite\n// after\nconst level = driver.options.type.startsWith('sqlite') ? undefined : 'READ COMMITTED';\nawait qr.startTransaction(level);\n","handlingStrategy":"validation","validationCode":"const SQLITE_LEVELS = new Set(['READ UNCOMMITTED', 'SERIALIZABLE']);\nfunction pickIsolationLevel(level, driverType): string | undefined {\n  if (!level) return undefined;\n  if (driverType.startsWith('sqlite') && !SQLITE_LEVELS.has(level)) return undefined;\n  return level;\n}\n","typeGuard":"const SQLITE_ISOLATION_LEVELS = ['READ UNCOMMITTED', 'SERIALIZABLE'] as const;\nfunction isSqliteIsolationLevel(x: unknown): x is (typeof SQLITE_ISOLATION_LEVELS)[number] {\n  return typeof x === 'string' && (SQLITE_ISOLATION_LEVELS as readonly string[]).includes(x);\n}\n","tryCatchPattern":"import { TypeORMError } from '@n8n/typeorm';\ntry {\n  await qr.startTransaction(requestedLevel);\n} catch (e) {\n  if (e instanceof TypeORMError && /SQLite only supports/.test(e.message)) {\n    // retry without an isolation level on sqlite\n    await qr.startTransaction(undefined);\n  } else {\n    throw e;\n  }\n}\n","preventionTips":["Do not request READ COMMITTED / REPEATABLE READ against sqlite.","Make isolation level env-aware and omit it for sqlite.","Add a unit test matrix covering sqlite + each isolation level.","Document the two-level SQLite isolation model for developers."],"tags":["typeorm","sqlite","transactions","database","isolation"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}