drizzle-team/drizzle-orm · error · Error
Set operator error (union / intersect / except): selected fi
Error message
Set operator error (union / intersect / except): selected fields are not the same or are in a different order
What it means
Thrown by the method-form set operator (.union/.intersect/.except on a select builder, select.ts:455) when the left and right selects do not expose the same selected-field keys in the same order (checked via order-sensitive haveSameKeys). SQL set operators require column-compatible result sets, so drizzle validates structurally before emitting the query.
Source
Thrown at drizzle-orm/src/sqlite-core/query-builders/select.ts:455
rightSelection:
| ((setOperators: GetSQLiteSetOperators) => SetOperatorRightSelect<TValue, TResult>)
| SetOperatorRightSelect<TValue, TResult>,
) => SQLiteSelectWithout<
this,
TDynamic,
SQLiteSetOperatorExcludedMethods,
true
> {
return (rightSelection) => {
const rightSelect = (typeof rightSelection === 'function'
? rightSelection(getSQLiteSetOperators())
: rightSelection) as TypedQueryBuilder<
any,
TResult
>;
if (!haveSameKeys(this.getSelectedFields(), rightSelect.getSelectedFields())) {
throw new Error(
'Set operator error (union / intersect / except): selected fields are not the same or are in a different order',
);
}
this.config.setOperators.push({ type, isAll, rightSelect });
return this as any;
};
}
/**
* Adds `union` set operator to the query.
*
* Calling this method will combine the result sets of the `select` statements and remove any duplicate rows that appear across them.
*
* See docs: {@link https://orm.drizzle.team/docs/set-operations#union}
*
* @example
*View on GitHub (pinned to b7862528fd)
Solutions
- Make both selects project exactly the same keys in the same order.
- If column types differ, alias and cast so the key sets align (e.g. both expose {id, label}).
- Use a shared selection-config object/type for both halves to prevent drift.
Example fix
// before
db.select({ id: users.id, label: users.name }).from(users)
.union(db.select({ id: posts.id, label2: posts.title }).from(posts)); // 'label' vs 'label2' -> throws
// after
db.select({ id: users.id, label: users.name }).from(users)
.union(db.select({ id: posts.id, label: posts.title }).from(posts)); Defensive patterns
Strategy: type-guard
Validate before calling
function assertSameSelection(left, right) {
const lk = Object.keys(left), rk = Object.keys(right);
if (lk.length !== rk.length || lk.some((k, i) => k !== rk[i])) {
throw new Error('Set-operator branches must share the same selected keys/order');
}
} Type guard
type SelectionOf<T> = { [K in keyof T]: T[K] };
function sameSelectionShape<L, R>(l: SelectionOf<L>, r: SelectionOf<R>): boolean {
const lk = Object.keys(l), rk = Object.keys(r);
return lk.length === rk.length && lk.every((k, i) => k === rk[i]);
} Prevention
- Share a single selection-config object across all union branches.
- Annotate each branch's .select() with the same type to catch drift at compile time.
- After editing one branch, update the others to keep keys/order aligned.
When it happens
Trigger: db.select({a: t1.a}).from(t1).union(db.select({b: t2.b}).from(t2)); selecting different columns, a different order, or a different count. Even identical column values under different keys fail because the comparison is on keys/order.
Common situations: Combining results from two tables with slightly different projections; adding a column to one side but not the other; reordering a select map during a refactor; using {a: true, b: true} on one side and {b: true, a: true} on the other.
Related errors
- Set operator error (union / intersect / except): selected fi
- Set operator error (union / intersect / except): selected fi
- Cannot pass undefined values to any set operator
- Set operator error (union / intersect / except): selected fi
- Cannot pass undefined values to any set operator
AI-assisted analysis of drizzle-team/drizzle-orm@b7862528fd (2026-08-03).
Data as JSON: /data/errors/64c1c38475ee474d.json.
Report an issue: GitHub.