{"record":{"id":"eb370794f3b1c593","repo":"hibernate/hibernate-orm","slug":"unable-to-find-physical-table","errorCode":null,"errorMessage":"Unable to find physical table: {}","messagePattern":"Unable to find physical table: (.+?)","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java","lineNumber":1039,"sourceCode":"\tpublic void addTableNameBinding(Identifier logicalName, Table table) {\n\t\tlogicalToPhysicalTableNameMap.put( logicalName, table.getNameIdentifier() );\n\t\tphysicalToLogicalTableNameMap.put( table.getNameIdentifier(), logicalName );\n\t}\n\n\t@Override\n\tpublic void addTableNameBinding(String schema, String catalog, String logicalName, String realTableName, Table denormalizedSuperTable) {\n\t\tfinal Identifier logicalNameIdentifier = getDatabase().toIdentifier( logicalName );\n\t\tfinal Identifier physicalNameIdentifier = getDatabase().toIdentifier( realTableName );\n\n\t\tlogicalToPhysicalTableNameMap.put( logicalNameIdentifier, physicalNameIdentifier );\n\t\tphysicalToLogicalTableNameMap.put( physicalNameIdentifier, logicalNameIdentifier );\n\t}\n\n\t@Override\n\tpublic String getLogicalTableName(Table ownerTable) {\n\t\tfinal Identifier logicalName = physicalToLogicalTableNameMap.get( ownerTable.getNameIdentifier() );\n\t\tif ( logicalName == null ) {\n\t\t\tthrow new MappingException( \"Unable to find physical table: \" + ownerTable.getName() );\n\t\t}\n\t\treturn logicalName.render();\n\t}\n\n\t@Override\n\tpublic String getPhysicalTableName(Identifier logicalName) {\n\t\tfinal Identifier physicalName = logicalToPhysicalTableNameMap.get( logicalName );\n\t\treturn physicalName == null ? null : physicalName.render();\n\t}\n\n\t@Override\n\tpublic String getPhysicalTableName(String logicalName) {\n\t\treturn getPhysicalTableName( getDatabase().toIdentifier( logicalName ) );\n\t}\n\n\t/**\n\t * Internal struct used to maintain xref between physical and logical column\n\t * names for a table.  Mainly this is used to ensure that the defined NamingStrategy","sourceCodeStart":1021,"sourceCodeEnd":1057,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java#L1021-L1057","documentation":"getLogicalTableName(Table) resolves a table object back to its logical name through the physical-to-logical map filled by addTableNameBinding. This MappingException means no binding was recorded for that physical name identifier — the Table was created or named outside the normal binding flow, or its Identifier differs (quoting or case) from the bound one.","triggerScenarios":"A Table instance constructed directly by custom code or a contributor instead of via the collector's addTable/addTableNameBinding; backtick-quoted names bound unquoted but looked up quoted (or vice versa); a PhysicalNamingStrategy producing different physical names at binding time versus lookup time.","commonSituations":"Custom MetadataContributors mixing programmatic tables with annotated mappings, switching PhysicalNamingStrategy mid-migration, and adding backtick quoting to some mappings but not others after moving to a case-sensitive database.","solutions":["Register every table through the collector (addTable plus addTableNameBinding) instead of constructing Table objects directly","Make quoting consistent: quote a table name in all its mappings or in none","Verify the PhysicalNamingStrategy yields identical physical names at bind time and at lookup time","If a third-party contributor creates tables, align it with the collector's binding helpers or report the incompatibility upstream"],"exampleFix":"<!-- before: quoted in one place, unquoted in another -->\n@Table(name = \"`order`\")\n<!-- elsewhere -->\n<join table=\"order\">...\n\n<!-- after: same quoting everywhere -->\n@Table(name = \"`order`\")\n<join table=\"`order`\">...","handlingStrategy":"try-catch","validationCode":"// verify a binding exists on the logical side before resolving physical tables\nfinal String physical = metadata.getPhysicalTableName( logicalName );\nif ( physical == null ) {\n    throw new IllegalStateException( \"No physical table bound for logical name: \" + logicalName );\n}","typeGuard":null,"tryCatchPattern":"try {\n    return mapping.getLogicalTableName( table );\n} catch ( MappingException e ) {\n    if ( e.getMessage() != null && e.getMessage().contains( \"Unable to find physical table\" ) ) {\n        // table created outside addTableNameBinding, or quoting/case mismatch on the Identifier\n        throw new IllegalStateException( \"Table \" + table.getName() + \" never bound logically — register it via addTableNameBinding\", e );\n    }\n    throw e;\n}","preventionTips":["Register tables only through the collector's addTable/addTableNameBinding helpers","Keep backtick quoting consistent across every mapping of the same table","Do not change PhysicalNamingStrategy between binding and lookup phases","Audit custom contributors for direct Table construction"],"tags":["hibernate","orm","java","bootstrap","table-mapping","naming-strategy"],"backgroundTag":"missing-table-binding","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}