typeorm/typeorm · error · TypeORMError

Entity to work with is not specified!

Error message

Entity to work with is not specified!

What it means

Thrown by the relationMetadata getter on QueryExpressionMap when mainAlias is null. This getter is used by RelationQueryBuilder (e.g. .relation(...).set/.add/.remove) which requires an owning entity. Without a main alias there is no entity to resolve relations against.

Source

Thrown at src/query-builder/QueryExpressionMap.ts:465

        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

        const relationMetadata =
            this.mainAlias.metadata.findRelationWithPropertyPath(
                this.relationPropertyPath,
            )
        if (!relationMetadata)
            throw new TypeORMError(
                `Relation ${this.relationPropertyPath} was not found in entity ${this.mainAlias.name}`,
            ) // todo: better message

        return relationMetadata
    }

    /**
     * Copies all properties of the current QueryExpressionMap into a new one.
     * Useful when QueryBuilder needs to create a copy of itself.
     */
    clone(): QueryExpressionMap {

View on GitHub (pinned to 04ff4daedc)

Solutions

  1. Always start relation operations from an entity-bound builder: dataSource.createQueryBuilder(User, 'user').relation(User, 'posts').
  2. Use the repository shorthand repo.relation(...) which binds the entity automatically.
  3. Ensure mainAlias is set before any .relation/.of/.set call.

Example fix

// before
await dataSource.createQueryBuilder()
  .relation(User, 'posts').of(user).set(post); // 492

// after
await dataSource.createQueryBuilder(User, 'user')
  .relation(User, 'posts').of(user).set(post);
// or simpler:
await repo.relation('posts').of(user).add(post);
Defensive patterns

Strategy: validation

Validate before calling

function assertRelationBuilderHasMainAlias(qb) {
  if (!qb.expressionMap.mainAlias) throw new Error('Relation ops require an entity main alias; use repo.relation() or createQueryBuilder(Entity).');
}

Type guard

function hasMainAlias(qb): boolean {
  return !!qb.expressionMap.mainAlias;
}

Prevention

When it happens

Trigger: You call dataSource.createQueryBuilder().relation(User, 'posts') without an entity/main alias, or call .relation() on a builder whose FROM was never set. relationMetadata runs before any relation lookup.

Common situations: Chaining .relation() on a fresh createQueryBuilder() with no entity. Constructing RelationQueryBuilder directly. Misusing the relation API on a subquery-based builder.

Related errors


AI-assisted analysis of typeorm/typeorm@04ff4daedc (2026-08-03). Data as JSON: /data/errors/65b67e377487bb26.json. Report an issue: GitHub.