typeorm/typeorm · error · TypeORMError

Index ${indexName}contains column that is missing in the ent

Error message

Index ${indexName}contains column that is missing in the entity (${entityName}): ${propertyPath}

What it means

Thrown during `IndexMetadata.build()` when an @Index decorator names a property path that is neither a real column nor a relation that owns a join column (@ManyToOne / owning @OneToOne). The builder walks `entityMetadata.columns` and `entityMetadata.relations` (filtering `isWithJoinColumn`); if neither matches the requested propertyPath string, it aborts because the index cannot be mapped to a physical database column.

Source

Thrown at src/metadata/IndexMetadata.ts:264

                        (column) => column.propertyPath === propertyPath,
                    )
                    if (columnWithSameName) {
                        return [columnWithSameName]
                    }
                    const relationWithSameName =
                        this.entityMetadata.relations.find(
                            (relation) =>
                                relation.isWithJoinColumn &&
                                relation.propertyName === propertyPath,
                        )
                    if (relationWithSameName) {
                        return relationWithSameName.joinColumns
                    }
                    const indexName = this.givenName
                        ? '"' + this.givenName + '" '
                        : ""
                    const entityName = this.entityMetadata.targetName
                    throw new TypeORMError(
                        `Index ${indexName}contains column that is missing in the entity (${entityName}): ` +
                            propertyPath,
                    )
                })
                .reduce((a, b) => a.concat(b))
        }

        this.columnNamesWithOrderingMap = Object.keys(map).reduce(
            (updatedMap, key) => {
                const column = this.entityMetadata.columns.find(
                    (column) => column.propertyPath === key,
                )
                if (column) updatedMap[column.databasePath] = map[key]

                return updatedMap
            },
            {} as { [key: string]: number },
        )

View on GitHub (pinned to 04ff4daedc)

Solutions

  1. Open the entity and verify each string in the @Index column array matches an actual @Column propertyPath or an owning relation (@ManyToOne/@OneToOne owner).
  2. If indexing a relation FK, make sure the relation is the owning side (has `@ManyToOne` or `@OneToOne(() => X, x => x.y)` with the join column on this entity).
  3. For embedded columns, prefix with the embed path (e.g. `"profile.address"`) or index from inside the embeddable class.

Example fix

// before
@Index("idx_owner", ["owner"])  // owner is @OneToMany inverse side -> no join column on this entity
export class Project {
  @OneToMany(() => User, u => u.project) owner: User[]
}

// after (index the owning FK column instead)
export class Project {
  @ManyToOne(() => User, { nullable: false })
  @JoinColumn({ name: "owner_id" })
  owner: User
}
// then @Index(["owner"]) resolves to the owner_id column
Defensive patterns

Strategy: validation

Validate before calling

// Validate @Index column names against the entity's own column list at bootstrap
function validateIndexColumns(
  entityColumns: string[],
  owningRelations: string[],
  indexColumns: string[],
): string[] {
  const valid = new Set([...entityColumns, ...owningRelations])
  return indexColumns.filter((c) => !valid.has(c))
}
// usage: throw if result is non-empty before calling dataSource.initialize()

Type guard

function isOwningRelation(meta: any, prop: string): boolean {
  const r = meta.relations.find((rel: any) => rel.propertyName === prop)
  return !!r && (r.isManyToOne || (r.isOneToOne && r.isOwning))
}

Prevention

When it happens

Trigger: `@Index("idx_x", ["nonexistent"])` on an entity where `nonexistent` is not a property; `@Index(["user"])` where `user` is a @OneToMany/@ManyToMany inverse side (no join column on this entity); typos in the column name array; referencing an embedded column by the wrong path (e.g. missing the embed prefix).

Common situations: Renaming a column but forgetting to update the @Index column list; using a relation property name that is the inverse (non-owning) side of a one-to-one or one-to-many; copy-pasting entity definitions; migrations that drift from entity metadata.

Related errors


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