{"id":"1514153557a9f495","repo":"drizzle-team/drizzle-orm","slug":"cannot-pass-undefined-values-to-any-set-operator-151415","errorCode":null,"errorMessage":"Cannot pass undefined values to any set operator","messagePattern":"Cannot pass undefined values to any set operator","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"drizzle-orm/src/sqlite-core/dialect.ts","lineNumber":445,"sourceCode":"\n\t\tconst finalQuery =\n\t\t\tsql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}`;\n\n\t\tif (setOperators.length > 0) {\n\t\t\treturn this.buildSetOperations(finalQuery, setOperators);\n\t\t}\n\n\t\treturn finalQuery;\n\t}\n\n\tbuildSetOperations(\n\t\tleftSelect: SQL,\n\t\tsetOperators: SQLiteSelectConfig['setOperators'],\n\t): SQL {\n\t\tconst [setOperator, ...rest] = setOperators;\n\n\t\tif (!setOperator) {\n\t\t\tthrow new Error('Cannot pass undefined values to any set operator');\n\t\t}\n\n\t\tif (rest.length === 0) {\n\t\t\treturn this.buildSetOperationQuery({ leftSelect, setOperator });\n\t\t}\n\n\t\t// Some recursive magic here\n\t\treturn this.buildSetOperations(\n\t\t\tthis.buildSetOperationQuery({ leftSelect, setOperator }),\n\t\t\trest,\n\t\t);\n\t}\n\n\tbuildSetOperationQuery({\n\t\tleftSelect,\n\t\tsetOperator: { type, isAll, rightSelect, limit, orderBy, offset },\n\t}: {\n\t\tleftSelect: SQL;","sourceCodeStart":427,"sourceCodeEnd":463,"githubUrl":"https://github.com/drizzle-team/drizzle-orm/blob/b7862528fd8fc39bc2653a6c18dad7c1f4e68d10/drizzle-orm/src/sqlite-core/dialect.ts#L427-L463","documentation":"Thrown by SQLiteDialect.buildSetOperations (dialect.ts:445) when the setOperators array passed in has undefined/null as its first element. Because the array is destructured as [setOperator, ...rest], a leading undefined means the caller pushed a malformed entry — drizzle cannot build a UNION/INTERSECT/EXCEPT without a defined operator config.","triggerScenarios":"Programmatically building the setOperators array and accidentally pushing undefined; a union/intersect/except chain where one branch evaluated to undefined; an internal API misuse that left a hole in the setOperators list.","commonSituations":"Dynamic query assembly that conditionally appends set operators and pushes the result of a ternary that resolved to undefined; version-mismatch where the internal config shape changed; hand-constructed select config.","solutions":["Filter undefined out of any dynamically built set-operator array before it reaches the query.","Use the public .union()/.intersect()/.except() builder methods rather than constructing setOperators by hand.","Assert each pushed entry is a defined object before appending."],"exampleFix":"// before\nconst ops = branches.map((b) => b ? { type: 'union', isAll: false, rightSelect: b } : undefined);\n// an undefined slipped into the array -> throws at build time\n\n// after\nconst ops = branches\n  .filter((b): b is Select => b !== undefined)\n  .map((b) => ({ type: 'union', isAll: false, rightSelect: b }));","handlingStrategy":"validation","validationCode":"function cleanSetOperators(ops) {\n  return ops.filter((op) => op != null && op.type && op.rightSelect);\n}","typeGuard":"const isSetOperator = (o): o is { type: string; rightSelect: unknown } =>\n  o != null && typeof o.type === 'string' && !!o.rightSelect;","tryCatchPattern":null,"preventionTips":["Prefer the public .union()/.intersect()/.except() API over hand-built setOperators arrays.","Always filter undefined out of dynamically assembled operator arrays.","Type the array strictly so TS rejects undefined entries."],"tags":["set-operators","union","query-builder","validation"],"analyzedSha":"b7862528fd8fc39bc2653a6c18dad7c1f4e68d10","analyzedAt":"2026-08-03T18:11:14.318Z","schemaVersion":2}