drizzle-team/drizzle-orm · error · Error
Alias "${tableName}" is already used in this query
Error message
Alias "${tableName}" is already used in this query What it means
PgUpdate.createJoin (update.ts:414) mirrors the select alias guard: it compares getTableLikeName(table) against existing join aliases in config.joins and throws on a duplicate. UPDATE...FROM in Postgres needs unique aliases for each referenced relation, so a repeat alias is rejected before SQL is built.
Source
Thrown at drizzle-orm/src/pg-core/query-builders/update.ts:415
if (is(table, PgTable)) {
return table[Table.Symbol.Columns];
} else if (is(table, Subquery)) {
return table._.selectedFields;
}
return table[ViewBaseConfig].selectedFields;
}
private createJoin<TJoinType extends JoinType>(
joinType: TJoinType,
): PgUpdateJoinFn<this, TDynamic, TJoinType> {
return ((
table: PgTable | Subquery | PgViewBase | SQL,
on: ((updateTable: TTable, from: TFrom) => SQL | undefined) | SQL | undefined,
) => {
const tableName = getTableLikeName(table);
if (typeof tableName === 'string' && this.config.joins.some((join) => join.alias === tableName)) {
throw new Error(`Alias "${tableName}" is already used in this query`);
}
if (typeof on === 'function') {
const from = this.config.from && !is(this.config.from, SQL)
? this.getTableLikeFields(this.config.from)
: undefined;
on = on(
new Proxy(
this.config.table[Table.Symbol.Columns],
new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }),
) as any,
from && new Proxy(
from,
new SelectionProxyHandler({ sqlAliasedBehavior: 'sql', sqlBehavior: 'sql' }),
) as any,
);
}
View on GitHub (pinned to b7862528fd)
Solutions
- Alias the second reference differently via a subquery (db.$with('alias').as(...)).
- For self-joins on the target table, use a distinct alias for the secondary reference.
- Track used aliases in dynamic builders and synthesize unique names.
Example fix
// before
db.update(t).set({...}).from(lookup).where(...)
.leftJoin(lookup, eq(lookup.id, t.lookupId)); // 'lookup' twice
// after
const l2 = db.$with('l2').as(db.select().from(lookup));
db.update(t).set({...}).with(l2).from(lookup).leftJoin(l2, eq(l2.id, t.otherId)).where(...); Defensive patterns
Strategy: validation
Validate before calling
function buildUpdateJoin(db: Db, target: PgTable, joins: { table: PgTable | SQL; on: SQL }[]) {
const used = new Set<string>();
let q = db.update(target).set({}).from(joins[0].table);
used.add(String(getTableLikeName(joins[0].table)));
for (const j of joins.slice(1)) {
const alias = getTableLikeName(j.table);
if (typeof alias === 'string' && used.has(alias)) {
throw new Error(`Alias "${alias}" already used in update`);
}
if (typeof alias === 'string') used.add(alias);
q = (q as any).leftJoin(j.table, j.on);
}
return q;
} Prevention
- Track aliases when building update-with-join dynamically.
- Alias repeated references via $with(...).as(...).
- Avoid reusing the target table name as a join alias.
When it happens
Trigger: Calling .from()/leftJoin()/innerJoin() on an update with a table or subquery whose alias was already used by the base table or a previous join; self-referential updates referencing the same table twice.
Common situations: Update-with-join patterns referencing the same lookup table twice; dynamic update builders appending joins without alias tracking; aliasing a subquery to collide with the target table.
Related errors
- Alias "${tableName}" is already used in this query
- Alias "${tableName}" is already used in this query
- Alias "${tableName}" is already used in this query
- Alias "${tableName}" is already used in this query
- You have an empty array for "${name}" enum values
AI-assisted analysis of drizzle-team/drizzle-orm@b7862528fd (2026-08-03).
Data as JSON: /data/errors/6dbdffe3c5293345.json.
Report an issue: GitHub.