n8n-io/n8n · error · TypeORMError

"${aliasName}" alias was not found. Maybe you forgot to join

Error message

"${aliasName}" alias was not found. Maybe you forgot to join it?

What it means

QueryExpressionMap.findAliasByName iterates this.aliases and throws TypeORMError when no alias with the given name was ever registered. Aliases are created by from/leftJoin/innerJoin etc.; referencing an alias name that does not match any of them is a programmer error.

Source

Thrown at packages/@n8n/typeorm/src/query-builder/QueryExpressionMap.ts:437

		if (aliasName) alias.name = aliasName;
		if (options.metadata) alias.metadata = options.metadata;
		if (options.target && !alias.hasMetadata)
			alias.metadata = this.connection.getMetadata(options.target);
		if (options.tablePath) alias.tablePath = options.tablePath;
		if (options.subQuery) alias.subQuery = options.subQuery;

		this.aliases.push(alias);
		return alias;
	}

	/**
	 * Finds alias with the given name.
	 * If alias was not found it throw an exception.
	 */
	findAliasByName(aliasName: string): Alias {
		const alias = this.aliases.find((alias) => alias.name === aliasName);
		if (!alias)
			throw new TypeORMError(`"${aliasName}" alias was not found. Maybe you forgot to join it?`);

		return alias;
	}

	findColumnByAliasExpression(aliasExpression: string): ColumnMetadata | undefined {
		const [aliasName, propertyPath] = aliasExpression.split('.');
		const alias = this.findAliasByName(aliasName);
		return alias.metadata.findColumnWithPropertyName(propertyPath);
	}

	/**
	 * Gets relation metadata of the relation this query builder works with.
	 *
	 * todo: add proper exceptions
	 */
	get relationMetadata(): RelationMetadata {
		if (!this.mainAlias) throw new TypeORMError(`Entity to work with is not specified!`); // todo: better message

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Audit every string condition in the failing builder for '<alias>.' prefixes and ensure each alias was created with a from()/join() call earlier in the chain.
  2. Prefer the lambda form qb.andWhere(alias + '.col = :v') where alias is a variable, not a literal, so renames propagate.
  3. Add the missing qb.leftJoin(Entity, aliasName) before the condition that uses it.

Example fix

// before
qb.andWhere('orders.total > :t', { t: 100 }); // 'orders' never joined
// after
qb.leftJoin('user.orders','orders').andWhere('orders.total > :t', { t: 100 });
Defensive patterns

Strategy: validation

Validate before calling

function assertAliasExists(qb: any, alias: string) {
  const map = qb.expressionMap;
  if (!map.aliases.some((a: any) => a.name === alias))
    throw new Error(`Alias '${alias}' not joined. Call .leftJoin/.innerJoin first.`);
}

Type guard

function isKnownAlias(qb: any, alias: string): boolean {
  return qb.expressionMap.aliases.some((a: any) => a.name === alias);
}

Prevention

When it happens

Trigger: Using qb.andWhere('otherAlias.col = :v') before calling qb.lefteftJoin('Entity','otherAlias'); typoing the alias name in a raw where string; referencing an alias after it was scoped out by a subquery; using getSql() of an inner builder whose alias name you reused verbatim outside its scope.

Common situations: Refactor that renames a join alias but leaves string-fragment conditions using the old name; copy-pasting a where fragment between builders whose join aliases differ; passing unqualified column names that TypeORM splits on '.' assuming alias.column.

Related errors


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