n8n-io/n8n · error · TypeORMError

Main alias is not set

Error message

Main alias is not set

What it means

QueryBuilder.alias getter throws when expressionMap.mainAlias is null. The main alias is set by select()/from()/into(); before any of those calls, there is no main alias and any method that reads .alias (e.g. escape resolution, getMainTableName, alias-dependent where clauses) fails. This is a developer-error guard, not a runtime recovery point.

Source

Thrown at packages/@n8n/typeorm/src/query-builder/QueryBuilder.ts:137

	// -------------------------------------------------------------------------
	// Abstract Methods
	// -------------------------------------------------------------------------

	/**
	 * Gets generated SQL query without parameters being replaced.
	 */
	abstract getQuery(): string;

	// -------------------------------------------------------------------------
	// Accessors
	// -------------------------------------------------------------------------

	/**
	 * Gets the main alias string used in this query builder.
	 */
	get alias(): string {
		if (!this.expressionMap.mainAlias) throw new TypeORMError(`Main alias is not set`); // todo: better exception

		return this.expressionMap.mainAlias.name;
	}

	// -------------------------------------------------------------------------
	// Public Methods
	// -------------------------------------------------------------------------

	/**
	 * Creates SELECT query.
	 * Replaces all previous selections if they exist.
	 */
	select(): SelectQueryBuilder<Entity>;

	/**
	 * Creates SELECT query and selects given data.
	 * Replaces all previous selections if they exist.
	 */

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Anchor the builder: createQueryBuilder(Entity, 'alias') or call .from(Entity, 'alias') / .into(Entity) / .select() first.
  2. For delete/update without a FROM entity, use dataSource.createQueryBuilder().delete().from(Entity).
  3. Ensure any conditional branch that returns a QueryBuilder always sets a main alias.

Example fix

// before
const qb = dataSource.createQueryBuilder();
qb.where('u.id = :id', { id }); // throws: no main alias

// after
const qb = dataSource.createQueryBuilder(User, 'u').where('u.id = :id', { id });
Defensive patterns

Strategy: validation

Validate before calling

function builderHasMainAlias(qb: { expressionMap: { mainAlias?: unknown } }): boolean {
  return qb.expressionMap.mainAlias != null;
}
if (!builderHasMainAlias(qb)) throw new Error('QueryBuilder has no main alias; call select/from/into first');

Type guard

function hasMainAlias(qb: { expressionMap: { mainAlias?: unknown } }): qb is { expressionMap: { mainAlias: NonNullable<unknown> } } {
  return qb.expressionMap.mainAlias != null;
}

Prevention

When it happens

Trigger: Calling createQueryBuilder() with no entity and then immediately invoking a method that reads this.alias (e.g. .where('alias.col = :v'), .orderBy, .getSql) before select/from/into. Also when chaining .delete()/.update() without a FROM alias on some drivers.

Common situations: Creating a blank QueryBuilder and forgetting to anchor it to an entity or table. Refactoring that drops the .from() call. Conditional builder construction that skips the anchor in a branch.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/41e86396a0d462a9. Report an issue: GitHub.