n8n-io/n8n · error · Error

Cannot find alias for relation at ${fullRelationPath}

Error message

Cannot find alias for relation at ${fullRelationPath}

What it means

QueryBuilder relation-path resolver throws when alias.metadata.hasRelationWithPropertyPath(part) is true (the relation exists on the entity) but no matching joinAttribute with an alias is found in expressionMap.joinAttributes. This means the property references a relation that was never joined, so no alias exists for it. The error is thrown from createPropertyPath iteration during where/orderBy/addSelect resolution.

Source

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

			if (alias.metadata.hasEmbeddedWithPropertyPath(part)) {
				// If this is an embedded then we should combine the two as part of our lookup.
				// Instead of just breaking, we keep going with this in case there's an embedded/relation
				// inside an embedded.
				propertyPathParts.unshift(`${propertyPathParts.shift()}.${propertyPathParts.shift()}`);
				continue;
			}

			if (alias.metadata.hasRelationWithPropertyPath(part)) {
				// If this is a relation then we should find the aliases
				// that match the relation & then continue further down
				// the property path
				const joinAttr = this.expressionMap.joinAttributes.find(
					(joinAttr) => joinAttr.relationPropertyPath === part,
				);

				if (!joinAttr?.alias) {
					const fullRelationPath = root.length > 0 ? `${root.join('.')}.${part}` : part;
					throw new Error(`Cannot find alias for relation at ${fullRelationPath}`);
				}

				alias = joinAttr.alias;
				root.push(...part.split('.'));
				propertyPathParts.shift();
				continue;
			}

			break;
		}

		if (!alias) {
			throw new Error(`Cannot find alias for property ${propertyPath}`);
		}

		// Remaining parts are combined back and used to find the actual property path
		const aliasPropertyPath = propertyPathParts.join('.');

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Add the corresponding leftJoin/innerJoin('alias.relation', 'relAlias') before referencing the relation property in where/orderBy/select.
  2. Ensure the join's relationPropertyPath matches the segment in the property path.
  3. If the relation is loaded eagerly, you still need an explicit join to reference its columns in the same query.
  4. Verify the alias used in the property path matches the join's parent alias.

Example fix

// before
qb.andWhere('u.members.role = :r', { r: 'admin' }); // members never joined

// after
qb.leftJoin('u.members', 'm').andWhere('m.role = :r', { r: 'admin' });
Defensive patterns

Strategy: validation

Validate before calling

function relationIsJoined(qb: { expressionMap: { joinAttributes: Array<{ relationPropertyPath?: string; alias?: unknown }> } }, relationPath: string, part: string): boolean {
  return qb.expressionMap.joinAttributes.some(ja => ja.relationPropertyPath === part && ja.alias != null);
}
if (!relationIsJoined(qb, path, segment)) throw new Error(`relation '${segment}' is not joined; add leftJoin before referencing its columns`);

Type guard

function relationAliasExists(qb: { expressionMap: { joinAttributes: Array<{ relationPropertyPath?: string; alias?: unknown }> } }, part: string): boolean {
  return qb.expressionMap.joinAttributes.some(ja => ja.relationPropertyPath === part && ja.alias != null);
}

Prevention

When it happens

Trigger: Writing .where('u.members.name = :n') or .orderBy('u.members.name') where 'members' is a @ManyToMany relation on User but no .leftJoin('u.members', 'm') was added. The relation exists in metadata but the join that creates the alias was omitted.

Common situations: Querying through a relation without joining it first. Renaming a join alias but not the where path. Assuming eager loading populates a joinable alias (it does not).

Related errors


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