drizzle-team/drizzle-orm · error · Error

Cannot pass undefined values to any set operator

Error message

Cannot pass undefined values to any set operator

What it means

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.

Source

Thrown at drizzle-orm/src/sqlite-core/dialect.ts:445

		const finalQuery =
			sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}`;

		if (setOperators.length > 0) {
			return this.buildSetOperations(finalQuery, setOperators);
		}

		return finalQuery;
	}

	buildSetOperations(
		leftSelect: SQL,
		setOperators: SQLiteSelectConfig['setOperators'],
	): SQL {
		const [setOperator, ...rest] = setOperators;

		if (!setOperator) {
			throw new Error('Cannot pass undefined values to any set operator');
		}

		if (rest.length === 0) {
			return this.buildSetOperationQuery({ leftSelect, setOperator });
		}

		// Some recursive magic here
		return this.buildSetOperations(
			this.buildSetOperationQuery({ leftSelect, setOperator }),
			rest,
		);
	}

	buildSetOperationQuery({
		leftSelect,
		setOperator: { type, isAll, rightSelect, limit, orderBy, offset },
	}: {
		leftSelect: SQL;

View on GitHub (pinned to b7862528fd)

Solutions

  1. Filter undefined out of any dynamically built set-operator array before it reaches the query.
  2. Use the public .union()/.intersect()/.except() builder methods rather than constructing setOperators by hand.
  3. Assert each pushed entry is a defined object before appending.

Example fix

// before
const ops = branches.map((b) => b ? { type: 'union', isAll: false, rightSelect: b } : undefined);
// an undefined slipped into the array -> throws at build time

// after
const ops = branches
  .filter((b): b is Select => b !== undefined)
  .map((b) => ({ type: 'union', isAll: false, rightSelect: b }));
Defensive patterns

Strategy: validation

Validate before calling

function cleanSetOperators(ops) {
  return ops.filter((op) => op != null && op.type && op.rightSelect);
}

Type guard

const isSetOperator = (o): o is { type: string; rightSelect: unknown } =>
  o != null && typeof o.type === 'string' && !!o.rightSelect;

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of drizzle-team/drizzle-orm@b7862528fd (2026-08-03). Data as JSON: /data/errors/1514153557a9f495.json. Report an issue: GitHub.