n8n-io/n8n · error · EntityPropertyNotFoundError

Property "${propertyPath}" was not found in "${metadata.targ

Error message

Property "${propertyPath}" was not found in "${metadata.targetName}". Make sure your query is correct.

What it means

Inside applyRelationsRecursively, when resolving a nested relation under relationLoadStrategy 'query' or 'join', TypeORM derives the next relationName and relationMetadata. If either is empty (the join/selection couldn't be found in the expression map), it throws EntityPropertyNotFoundError with the original propertyPath and the parent entity targetName. This indicates a relation path whose prefix doesn't correspond to any loaded relation alias.

Source

Thrown at packages/@n8n/typeorm/src/find-options/FindOptionsUtils.ts:329

			);

			// try to find sub-relations
			let relationMetadata: EntityMetadata | undefined;
			let relationName: string | undefined;

			if (qb.expressionMap.relationLoadStrategy === 'query') {
				relationMetadata = relation.inverseEntityMetadata;
				relationName = relationAlias;
			} else {
				const join = qb.expressionMap.joinAttributes.find(
					(join) => join.entityOrProperty === selection,
				);
				relationMetadata = join!.metadata!;
				relationName = join!.alias.name;
			}

			if (!relationName || !relationMetadata) {
				throw new EntityPropertyNotFoundError(relation.propertyPath, metadata);
			}

			this.applyRelationsRecursively(
				qb,
				allRelations,
				relationName,
				relationMetadata,
				prefix ? prefix + '.' + relation.propertyPath : relation.propertyPath,
			);

			// join the eager relations of the found relation
			// Only supported for "join" relationLoadStrategy
			if (qb.expressionMap.relationLoadStrategy === 'join') {
				const relMetadata = metadata.relations.find(
					(metadata) => metadata.propertyName === relation.propertyPath,
				);
				if (relMetadata) {
					this.joinEagerRelations(qb, relationAlias, relMetadata.inverseEntityMetadata);

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Verify each segment of a dotted relation path is a relation; for terminal columns use `select`, not `relations`.
  2. Keep relationLoadStrategy consistent with the query shape (join strategy requires the joins to exist in the expression map).
  3. When using a custom query builder with find-options, ensure aliases match what setFindOptions expects.
  4. Build the relations array incrementally to localize the failing segment.

Example fix

// before
await repo.find({ relations: ['profile.address.city'] });
// `city` is a column on Address, not a relation

// after - relations only for related entities, select for columns
@Entity()
class Profile { @OneToOne(() => Address) address!: Address; }
class Address { @Column() city!: string; }
await repo.find({ relations: ['profile', 'profile.address'] });
Defensive patterns

Strategy: validation

Validate before calling

function validateNestedRelations<Entity>(meta: import('@n8n/typeorm').EntityMetadata<Entity>, relations: readonly string[]): void {
  for (const path of relations) {
    let m = meta;
    const segs = path.split('.');
    segs.forEach((seg, i) => {
      const rel = m.relations.find(x => x.propertyPath === seg);
      if (!rel) {
        const isLast = i === segs.length - 1;
        if (isLast && m.columns.some(c => c.propertyPath === seg)) {
          throw new Error(`'${seg}' is a column, not a relation — use select, not relations`);
        }
        throw new Error(`relation segment '${seg}' not found on ${m.name}`);
      }
      m = rel.inverseEntityMetadata;
    });
  }
}
validateNestedRelations(connection.getMetadata(Entity), options.relations ?? []);
await repo.find(options);

Type guard

function isTerminalColumn(meta: import('@n8n/typeorm').EntityMetadata<any>, seg: string): boolean {
  return meta.columns.some(c => c.propertyPath === seg);
}

Prevention

When it happens

Trigger: Requesting `relations: ['profile.address.city']` where `profile.address` is loaded but `city` isn't a relation of Address (it's a column); relationLoadStrategy mismatch (query vs join) where the expected join attribute wasn't created; manually-built query builders where the alias expected by recursive resolution was renamed; selecting a relation path before joining it.

Common situations: Deep nested relation paths where a mid-segment is a column not a relation; switching relationLoadStrategy without updating the relations array; custom query builder where aliases don't match what the find-options utility expects; copy-pasting a path from a different entity.

Related errors


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