{"record":{"id":"7aec4d213db905fd","repo":"n8n-io/n8n","slug":"the-optimistic-lock-can-be-used-only-with-getone","errorCode":null,"errorMessage":"The optimistic lock can be used only with getOne() method.","messagePattern":"The optimistic lock can be used only with getOne\\(\\) method\\.","errorType":"exception","errorClass":"OptimisticLockCanNotBeUsedError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/typeorm/src/query-builder/SelectQueryBuilder.ts","lineNumber":1475,"sourceCode":"\t * Disables the global condition of \"non-deleted\" for the entity with delete date columns.\n\t */\n\twithDeleted(): this {\n\t\tthis.expressionMap.withDeleted = true;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets first raw result returned by execution of generated query builder sql.\n\t */\n\tasync getRawOne<T = any>(): Promise<T | undefined> {\n\t\treturn (await this.getRawMany())[0];\n\t}\n\n\t/**\n\t * Gets all raw results returned by execution of generated query builder sql.\n\t */\n\tasync getRawMany<T = any>(): Promise<T[]> {\n\t\tif (this.expressionMap.lockMode === 'optimistic') throw new OptimisticLockCanNotBeUsedError();\n\n\t\tthis.expressionMap.queryEntity = false;\n\t\tconst queryRunner = this.obtainQueryRunner();\n\t\tlet transactionStartedByUs: boolean = false;\n\t\ttry {\n\t\t\t// start transaction if it was enabled\n\t\t\tif (this.expressionMap.useTransaction === true && queryRunner.isTransactionActive === false) {\n\t\t\t\tawait queryRunner.startTransaction();\n\t\t\t\ttransactionStartedByUs = true;\n\t\t\t}\n\n\t\t\tconst results = await this.loadRawResults(queryRunner);\n\n\t\t\t// close transaction if we started it\n\t\t\tif (transactionStartedByUs) {\n\t\t\t\tawait queryRunner.commitTransaction();\n\t\t\t}\n","sourceCodeStart":1457,"sourceCodeEnd":1493,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/typeorm/src/query-builder/SelectQueryBuilder.ts#L1457-L1493","documentation":"Thrown as OptimisticLockCanNotBeUsedError from getRawMany (and therefore getRawOne, which delegates to it) when expressionMap.lockMode === 'optimistic'. Optimistic locking requires materializing entity metadata to compare version columns, which the raw-result path does not do, so it refuses to run.","triggerScenarios":"Calling `.setLock('optimistic', version).getRawMany()` or `.getRawOne()`. Mixing `.setLock('optimistic', ...)` with raw projections.","commonSituations":"Refactoring a query from getOne() to getRawMany() for performance while leaving an optimistic-lock set; copy-paste of a query-builder chain across read paths; enabling optimistic locking globally in a base repository method that is also used for raw reads.","solutions":["Use getOne() (or getMany()) instead of getRawMany()/getRawOne() when optimistic locking is set.","If you need raw results, remove the optimistic lock for that query path: split into two query builders.","Assert lockMode before choosing the read method so the mismatch is caught in tests."],"exampleFix":"// before\nqb.setLock('optimistic', version).getRawOne();\n// after\nqb.setLock('optimistic', version).getOne();","handlingStrategy":"validation","validationCode":"function assertSafeForRaw(qb: SelectQueryBuilder<any>): void {\n  // Optimistic locks cannot be used with raw reads\n  if ((qb as any).expressionMap?.lockMode === 'optimistic') {\n    throw new Error('Optimistic lock is incompatible with getRawMany/getRawOne; use getOne/getMany or drop the lock.');\n  }\n}","typeGuard":"function isOptimisticLockQuery(qb: { expressionMap?: { lockMode?: string } }): boolean {\n  return qb.expressionMap?.lockMode === 'optimistic';\n}","tryCatchPattern":"try {\n  return await qb.getRawMany();\n} catch (e) {\n  if (e?.name === 'OptimisticLockCanNotBeUsedError' || /optimistic lock/i.test(e?.message ?? '')) {\n    return await qb.getMany(); // fall back to entity read\n  }\n  throw e;\n}","preventionTips":["Decide per query path whether you need entities (getOne/getMany) or raw rows (getRawOne/getRawMany).","Never set an optimistic lock on a query builder reused for raw reads.","Add a unit test that asserts raw-read methods throw when an optimistic lock is configured."],"tags":["typeorm","query-builder","optimistic-locking","concurrency"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}