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 when joining a table in a SQLite SELECT (select.ts:223) whose alias (the table's own name or an alias() string) already matches an alias registered by a previous join in the same query. Drizzle requires unique aliases so the generated SQL is unambiguous.

Source

Thrown at drizzle-orm/src/sqlite-core/query-builders/select.ts:223

	}

	private createJoin<TJoinType extends JoinType>(
		joinType: TJoinType,
	): 'cross' extends TJoinType ? SQLiteSelectCrossJoinFn<this, TDynamic>
		: SQLiteSelectJoinFn<this, TDynamic, TJoinType>
	{
		return (
			table: SQLiteTable | Subquery | SQLiteViewBase | SQL,
			on?: ((aliases: TSelection) => SQL | undefined) | SQL | undefined,
		) => {
			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

  1. Alias the second instance: table.as('alias2') and use that alias throughout the join and selection.
  2. Rename a conflicting subquery alias to something unique.
  3. Audit the joins array for duplicate alias strings before building.

Example fix

// before
db.select().from(posts)
  .leftJoin(posts, eq(posts.id, posts.parentId)); // 'posts' used twice

// after
const replies = posts.as('replies');
db.select().from(posts)
  .leftJoin(replies, eq(replies.parentId, posts.id));
Defensive patterns

Strategy: validation

Validate before calling

function assertUniqueAlias(joins, alias) {
  if (joins.some((j) => j.alias === alias)) {
    throw new Error(`Alias ${alias} already used`);
  }
}

Prevention

When it happens

Trigger: Joining the same table twice without aliasing one of them; joining two tables that share an alias string; .leftJoin(t2.as('x')) after already joining something aliased 'x'. The base FROM table's name also counts as a used alias.

Common situations: Self-joins (post↔post) without .as(); joining a table and a view/subquery that share a name; alias collisions after renaming; copy-pasting a join block.

Related errors


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