{"record":{"id":"378db8bcbd5830f9","repo":"hibernate/hibernate-orm","slug":"unable-to-resolve-tablemapping-for-selectable-s","errorCode":null,"errorMessage":"Unable to resolve TableMapping for selectable - %s","messagePattern":"Unable to resolve TableMapping for selectable - (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java","lineNumber":1829,"sourceCode":"\t\tfinal var propertyLaziness = persister.getPropertyLaziness();\n\t\tfor ( int dirtyField : dirtyFields ) {\n\t\t\tif ( propertyLaziness[dirtyField] ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic EntityTableMapping physicalTableMappingForMutation(\n\t\t\tEntityPersister persister, SelectableMapping selectableMapping) {\n\t\tfinal String tableNameForMutation = persister.physicalTableNameForMutation( selectableMapping );\n\t\tfor ( var tableMapping : persister.getTableMappings() ) {\n\t\t\tif ( tableNameForMutation.equals( tableMapping.getTableName() ) ) {\n\t\t\t\treturn tableMapping;\n\t\t\t}\n\t\t}\n\n\t\tthrow new IllegalArgumentException( \"Unable to resolve TableMapping for selectable - \" + selectableMapping );\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"UpdateCoordinatorStandard(\" + entityPersister().getEntityName() + \")\";\n\t}\n}\n","sourceCodeStart":1811,"sourceCodeEnd":1837,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java#L1811-L1837","documentation":"Before applying a mutation, UpdateCoordinatorStandard.physicalTableMappingForMutation resolves the dirty selectable's physical table via persister.physicalTableNameForMutation() and matches it against persister.getTableMappings(). IllegalArgumentException 'Unable to resolve TableMapping for selectable' means the selectable's owning table name matches none of the persister's tables - the attribute is being mutated through a persister that does not own its table, typically a mapping inconsistency.","triggerScenarios":"hbm.xml <column table=\"other\"/> or @Column(table=...) pointing at a table not declared as @SecondaryTable/join on the same entity; secondary-table names mismatched by case or quoting (case-sensitive databases); custom types marking foreign-table columns dirty; edge inheritance paths mutating subclass-owned attributes through the wrong persister.","commonSituations":"Renaming a secondary table in one place but not everywhere; hand-edited hbm.xml join mappings; physical naming strategies rewriting secondary table names; PostgreSQL/Oracle case sensitivity around quoted identifiers.","solutions":["Make every @Column(table=...) / <column table=...> value exactly match a @SecondaryTable or join name of the same entity","Verify the physical naming strategy output (case, quoting) for secondary tables matches the declared names","Mark columns owned by other tables insertable=false updatable=false so they never appear in mutations","Reduce to a minimal entity; if the mapping looks consistent, report it to Hibernate (HHH)"],"exampleFix":"// before: column references a table not owned by the entity\n@Entity\n@SecondaryTable(name = \"user_details\")\npublic class User {\n    @Column(table = \"user_detail\", insertable = false, updatable = true) // typo -> unresolvable\n    String bio;\n}\n\n// after: table attribute matches the declared secondary table\n@Column(table = \"user_details\")\nString bio;","handlingStrategy":"validation","validationCode":"// after Metadata build: every updatable column's table must be owned by its entity\nfor (PersistentClass pc : metadata.getEntityBindings()) {\n    Set<String> owned = new HashSet<>();\n    owned.add(pc.getRootTable().getName());\n    pc.getJoinClosureIterator().forEachRemaining(j -> owned.add(j.getTable().getName()));\n    pc.getPropertyClosureIterator().forEachRemaining(prop ->\n        prop.getColumnIterator().forEachRemaining(col -> {\n            String t = col.getValue().getTable().getName();\n            if (!owned.contains(t) && col.isQuoted() || !owned.contains(t)) {\n                // flag columns resolving to tables this entity does not own\n            }\n        }));\n}","typeGuard":null,"tryCatchPattern":"try { session.update(entity); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"resolve TableMapping\")) { /* align @Column(table=...) with the entity's secondary tables */ } throw e; }","preventionTips":["Keep @Column(table=...) values in lockstep with @SecondaryTable declarations during renames","Mark foreign-owned columns insertable=false updatable=false","Beware case-sensitive databases: match secondary-table names exactly including quoting"],"tags":["hibernate","orm","secondary-table","column-mapping","mutation","update"],"backgroundTag":"column-table-mapping-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}