{"record":{"id":"36e8b0d93578d15a","repo":"n8n-io/n8n","slug":"cte-options-columnnames-length-cte-options-colu","errorCode":null,"errorMessage":"cte.options.columnNames length (${cte.options.columnNames.length}) doesn't match subquery select list length ${cte.queryBuilder.expressionMap.selects.length} (CTE: ${cte.alias})","messagePattern":"cte\\.options\\.columnNames length \\((.+?)\\) doesn't match subquery select list length (.+?) \\(CTE: (.+?)\\)","errorType":"exception","errorClass":"TypeORMError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/typeorm/src/query-builder/QueryBuilder.ts","lineNumber":1033,"sourceCode":"\t\t\t\tif (\n\t\t\t\t\t!this.connection.driver.cteCapabilities.writable &&\n\t\t\t\t\t!InstanceChecker.isSelectQueryBuilder(cte.queryBuilder)\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeORMError(\n\t\t\t\t\t\t`Only select queries are supported in CTEs in ${this.connection.options.type} (CTE: ${cte.alias})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthis.setParameters(cte.queryBuilder.getParameters());\n\t\t\t}\n\t\t\tlet cteHeader = this.escape(cte.alias);\n\t\t\tif (cte.options.columnNames) {\n\t\t\t\tconst escapedColumnNames = cte.options.columnNames.map((column) => this.escape(column));\n\t\t\t\tif (InstanceChecker.isSelectQueryBuilder(cte.queryBuilder)) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tcte.queryBuilder.expressionMap.selects.length &&\n\t\t\t\t\t\tcte.options.columnNames.length !== cte.queryBuilder.expressionMap.selects.length\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new TypeORMError(\n\t\t\t\t\t\t\t`cte.options.columnNames length (${cte.options.columnNames.length}) doesn't match subquery select list length ${cte.queryBuilder.expressionMap.selects.length} (CTE: ${cte.alias})`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcteHeader += `(${escapedColumnNames.join(', ')})`;\n\t\t\t}\n\t\t\tconst recursiveClause =\n\t\t\t\tcte.options.recursive && databaseRequireRecusiveHint ? 'RECURSIVE' : '';\n\t\t\tlet materializeClause = '';\n\t\t\tif (\n\t\t\t\tthis.connection.driver.cteCapabilities.materializedHint &&\n\t\t\t\tcte.options.materialized !== undefined\n\t\t\t) {\n\t\t\t\tmaterializeClause = cte.options.materialized ? 'MATERIALIZED' : 'NOT MATERIALIZED';\n\t\t\t}\n\n\t\t\treturn [recursiveClause, cteHeader, 'AS', materializeClause, `(${cteBodyExpression})`]\n\t\t\t\t.filter(Boolean)","sourceCodeStart":1015,"sourceCodeEnd":1051,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/typeorm/src/query-builder/QueryBuilder.ts#L1015-L1051","documentation":"createCteExpression() throws when cte.options.columnNames length differs from cte.queryBuilder.expressionMap.selects length. A CTE with an explicit column list (WITH name (a, b) AS ...) must have exactly as many columns as the subquery's select list; the database would reject the mismatch. TypeORM checks this only for SelectQueryBuilder bodies with non-empty selects.","triggerScenarios":"Calling .addCommonTableExpression(selectQb, 'cte', { columnNames: ['a', 'b', 'c'] }) when selectQb selects only two columns (or vice versa). Mismatch arises from adding/removing a select in the body without updating columnNames.","commonSituations":"Naming CTE columns explicitly and then editing the body's select list. Copying a CTE config from a query with a different projection. Forgetting that addSelect changes the select count.","solutions":["Align columnNames length with the body's select list; either drop columnNames (let the DB infer) or update both together.","When using addSelect on the body, recount and update the columnNames array.","Omit columnNames entirely if you don't need explicit CTE column aliases.","Write a unit test asserting columnNames.length === body.expressionMap.selects.length for composed CTEs."],"exampleFix":"// before\nconst body = dataSource.createQueryBuilder().select('a').addSelect('b').from(T, 't');\nqb.addCommonTableExpression(body, 'cte', { columnNames: ['a', 'b', 'c'] }); // 3 != 2\n\n// after\nqb.addCommonTableExpression(body, 'cte', { columnNames: ['a', 'b'] });","handlingStrategy":"validation","validationCode":"function cteColumnsMatch(body: { expressionMap: { selects: unknown[] } }, columnNames?: string[]): boolean {\n  if (!columnNames) return true;\n  if (body.expressionMap.selects.length === 0) return true;\n  return columnNames.length === body.expressionMap.selects.length;\n}\nif (!cteColumnsMatch(bodyQb, opts.columnNames)) throw new Error('cte columnNames length must equal select list length');","typeGuard":"function cteColumnsAligned(body: { expressionMap: { selects: unknown[] } }, columnNames?: string[]): boolean {\n  if (!columnNames || body.expressionMap.selects.length === 0) return true;\n  return columnNames.length === body.expressionMap.selects.length;\n}","tryCatchPattern":null,"preventionTips":["Keep columnNames length in sync with the body select list; update both together.","Omit columnNames if explicit CTE column aliases are unnecessary.","Recount selects after addSelect changes.","Unit-test composed CTEs to assert column alignment."],"tags":["query-builder","cte","validation"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}