{"id":"176e722e3499e958","repo":"typeorm/typeorm","slug":"index-indexname-contains-column-that-is-missing","errorCode":null,"errorMessage":"Index ${indexName}contains column that is missing in the entity (${entityName}): ${propertyPath}","messagePattern":"Index (.+?)contains column that is missing in the entity \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"TypeORMError","httpStatus":null,"severity":"error","filePath":"src/metadata/IndexMetadata.ts","lineNumber":264,"sourceCode":"                        (column) => column.propertyPath === propertyPath,\n                    )\n                    if (columnWithSameName) {\n                        return [columnWithSameName]\n                    }\n                    const relationWithSameName =\n                        this.entityMetadata.relations.find(\n                            (relation) =>\n                                relation.isWithJoinColumn &&\n                                relation.propertyName === propertyPath,\n                        )\n                    if (relationWithSameName) {\n                        return relationWithSameName.joinColumns\n                    }\n                    const indexName = this.givenName\n                        ? '\"' + this.givenName + '\" '\n                        : \"\"\n                    const entityName = this.entityMetadata.targetName\n                    throw new TypeORMError(\n                        `Index ${indexName}contains column that is missing in the entity (${entityName}): ` +\n                            propertyPath,\n                    )\n                })\n                .reduce((a, b) => a.concat(b))\n        }\n\n        this.columnNamesWithOrderingMap = Object.keys(map).reduce(\n            (updatedMap, key) => {\n                const column = this.entityMetadata.columns.find(\n                    (column) => column.propertyPath === key,\n                )\n                if (column) updatedMap[column.databasePath] = map[key]\n\n                return updatedMap\n            },\n            {} as { [key: string]: number },\n        )","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/typeorm/typeorm/blob/04ff4daedcf60fa4ffd0d5d33bbafaac1a9bbc96/src/metadata/IndexMetadata.ts#L246-L282","documentation":"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.","triggerScenarios":"`@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).","commonSituations":"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.","solutions":["Open the entity and verify each string in the @Index column array matches an actual @Column propertyPath or an owning relation (@ManyToOne/@OneToOne owner).","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).","For embedded columns, prefix with the embed path (e.g. `\"profile.address\"`) or index from inside the embeddable class."],"exampleFix":"// before\n@Index(\"idx_owner\", [\"owner\"])  // owner is @OneToMany inverse side -> no join column on this entity\nexport class Project {\n  @OneToMany(() => User, u => u.project) owner: User[]\n}\n\n// after (index the owning FK column instead)\nexport class Project {\n  @ManyToOne(() => User, { nullable: false })\n  @JoinColumn({ name: \"owner_id\" })\n  owner: User\n}\n// then @Index([\"owner\"]) resolves to the owner_id column","handlingStrategy":"validation","validationCode":"// Validate @Index column names against the entity's own column list at bootstrap\nfunction validateIndexColumns(\n  entityColumns: string[],\n  owningRelations: string[],\n  indexColumns: string[],\n): string[] {\n  const valid = new Set([...entityColumns, ...owningRelations])\n  return indexColumns.filter((c) => !valid.has(c))\n}\n// usage: throw if result is non-empty before calling dataSource.initialize()","typeGuard":"function isOwningRelation(meta: any, prop: string): boolean {\n  const r = meta.relations.find((rel: any) => rel.propertyName === prop)\n  return !!r && (r.isManyToOne || (r.isOneToOne && r.isOwning))\n}","tryCatchPattern":null,"preventionTips":["After renaming a column, grep for the old name in @Index decorator arrays.","Use a typed decorator helper or lint rule that only allows known column names.","Initialize the DataSource in tests to surface metadata errors early."],"tags":["metadata","index","schema-build","entity-definition"],"analyzedSha":"04ff4daedcf60fa4ffd0d5d33bbafaac1a9bbc96","analyzedAt":"2026-08-03T18:27:32.281Z","schemaVersion":2}