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 MySqlDialect.buildSetOperations (line 495) when destructuring setOperators yields undefined as the first element. This is a defensive internal invariant: a set operator entry was undefined/missing, which should not be reachable through the public API.

Source

Thrown at drizzle-orm/src/mysql-core/dialect.ts:495

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

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

		return finalQuery;
	}

	buildSetOperations(
		leftSelect: SQL,
		setOperators: MySqlSelectConfig['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. Avoid manually pushing into query config.setOperators - use the .union()/.intersect()/.except() builder methods.
  2. Ensure you're not passing undefined to addSetOperators; filter out undefined entries first.
  3. If using a forked/patched Drizzle, diff against upstream set-operator handling.
  4. Upgrade to the latest Drizzle version in case this is a fixed internal regression.

Example fix

// before (advanced misuse)
(query as any).config.setOperators.push(undefined);
query.getSQL(); // throws

// after - only push valid operator objects
const op = { type: 'union', isAll: false, rightSelect: otherQuery };
(query as any).config.setOperators.push(op);
Defensive patterns

Strategy: validation

Validate before calling

// Don't push undefined into config.setOperators
const ops = candidateSetOperators.filter((o) => o != null) as NonNullable<typeof candidateSetOperators[number]>[];
if (ops.length === 0) return; // nothing to build
query.addSetOperators(ops);

Type guard

function isSetOperator(v: unknown): v is MySqlSelectConfig['setOperators'][number] {
  return v != null && typeof v === 'object' && 'type' in v && 'rightSelect' in v;
}

Prevention

When it happens

Trigger: The setOperators array on MySqlSelectConfig contains an undefined entry before being built. Not normally reachable via db.select().union() since those validate inputs; would require manually mutating config.setOperators with undefined or an internal bug.

Common situations: Internal/advanced misuse where config.setOperators was patched to contain undefined; version mismatch or monkey-patching of Drizzle internals; extremely rare in normal usage.

Related errors


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