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
Thrown by createJoin inside MySqlSelectQueryBuilderBase (line 273) when a join is added whose alias already exists among the previously registered joins. Drizzle prevents duplicate aliases because they'd produce ambiguous SQL.
Source
Thrown at drizzle-orm/src/mysql-core/query-builders/select.ts:273
: 'Index hint configuration is allowed only for MySqlTable and not for subqueries or views',
) => {
const isCrossJoin = joinType === 'cross';
let on = (isCrossJoin ? undefined : a) as (
| ((aliases: TSelection) => SQL | undefined)
| SQL
| undefined
);
const onIndex = (isCrossJoin ? a : b) as TJoinedTable extends MySqlTable ? IndexConfig
: 'Index hint configuration is allowed only for MySqlTable and not for subqueries or views';
const baseTableName = this.tableName;
const tableName = getTableLikeName(table);
// store all tables used in a query
for (const item of extractUsedTable(table)) this.usedTables.add(item);
if (typeof tableName === 'string' && this.config.joins?.some((join) => join.alias === tableName)) {
throw new Error(`Alias "${tableName}" is already used in this query`);
}
if (!this.isPartialSelect) {
// If this is the first join and this is not a partial select and we're not selecting from raw SQL, "move" the fields from the main table to the nested object
if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === 'string') {
this.config.fields = {
[baseTableName]: this.config.fields,
};
}
if (typeof tableName === 'string' && !is(table, SQL)) {
const selection = is(table, Subquery)
? table._.selectedFields
: is(table, View)
? table[ViewBaseConfig].selectedFields
: table[Table.Symbol.Columns];
this.config.fields[tableName] = selection;
}
}View on GitHub (pinned to b7862528fd)
Solutions
- Alias the second instance distinctly: .leftJoin(pets.as('pet1'), ...).leftJoin(pets.as('pet2'), ...).
- Remove the duplicate join if it was added by mistake.
- For self-joins, create two aliased references to the same table up front and join each once.
Example fix
// before
db.select().from(users)
.leftJoin(pets, eq(users.id, pets.ownerId))
.leftJoin(pets, eq(users.id, pets.coOwnerId)); // duplicate 'pets'
// after - alias the second
const pet1 = pets.as('pet1');
const pet2 = pets.as('pet2');
db.select().from(users)
.leftJoin(pet1, eq(users.id, pet1.ownerId))
.leftJoin(pet2, eq(users.id, pet2.coOwnerId)); Defensive patterns
Strategy: validation
Validate before calling
const usedAliases = new Set<string>();
function assertAlias(alias: string) {
if (usedAliases.has(alias)) throw new Error(`Alias ${alias} already used`);
usedAliases.add(alias);
} Type guard
function aliasAvailable(existing: string[], alias: string): boolean {
return !existing.includes(alias);
} Prevention
- Use distinct aliases (.as('name')) for repeated table joins.
- Track used aliases when building joins dynamically.
- Avoid joining the same table twice without aliasing.
When it happens
Trigger: Calling two joins with the same table/alias, e.g. .leftJoin(pets, ...).leftJoin(pets, ...) or joining an aliased table whose alias was already used. The check scans config.joins for a matching alias.
Common situations: Self-joins done without distinct aliases; joining the same relation twice (e.g. owner + co-owner); copy-pasting a join without renaming the alias.
Related errors
- Your "${f.path.join('->')}" field references a column "${tab
- Set operator error (union / intersect / except): selected fi
- 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/1a9726328d8177e8.json.
Report an issue: GitHub.