hibernate/hibernate-orm · error · MappingException
Unable to find physical table: {}
Error message
Unable to find physical table: {} What it means
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.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java:1039
public void addTableNameBinding(Identifier logicalName, Table table) {
logicalToPhysicalTableNameMap.put( logicalName, table.getNameIdentifier() );
physicalToLogicalTableNameMap.put( table.getNameIdentifier(), logicalName );
}
@Override
public void addTableNameBinding(String schema, String catalog, String logicalName, String realTableName, Table denormalizedSuperTable) {
final Identifier logicalNameIdentifier = getDatabase().toIdentifier( logicalName );
final Identifier physicalNameIdentifier = getDatabase().toIdentifier( realTableName );
logicalToPhysicalTableNameMap.put( logicalNameIdentifier, physicalNameIdentifier );
physicalToLogicalTableNameMap.put( physicalNameIdentifier, logicalNameIdentifier );
}
@Override
public String getLogicalTableName(Table ownerTable) {
final Identifier logicalName = physicalToLogicalTableNameMap.get( ownerTable.getNameIdentifier() );
if ( logicalName == null ) {
throw new MappingException( "Unable to find physical table: " + ownerTable.getName() );
}
return logicalName.render();
}
@Override
public String getPhysicalTableName(Identifier logicalName) {
final Identifier physicalName = logicalToPhysicalTableNameMap.get( logicalName );
return physicalName == null ? null : physicalName.render();
}
@Override
public String getPhysicalTableName(String logicalName) {
return getPhysicalTableName( getDatabase().toIdentifier( logicalName ) );
}
/**
* Internal struct used to maintain xref between physical and logical column
* names for a table. Mainly this is used to ensure that the defined NamingStrategyView on GitHub (pinned to fad1729dce)
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
Example fix
<!-- before: quoted in one place, unquoted in another --> @Table(name = "`order`") <!-- elsewhere --> <join table="order">... <!-- after: same quoting everywhere --> @Table(name = "`order`") <join table="`order`">...
Defensive patterns
Strategy: try-catch
Validate before calling
// verify a binding exists on the logical side before resolving physical tables
final String physical = metadata.getPhysicalTableName( logicalName );
if ( physical == null ) {
throw new IllegalStateException( "No physical table bound for logical name: " + logicalName );
} Try / catch
try {
return mapping.getLogicalTableName( table );
} catch ( MappingException e ) {
if ( e.getMessage() != null && e.getMessage().contains( "Unable to find physical table" ) ) {
// table created outside addTableNameBinding, or quoting/case mismatch on the Identifier
throw new IllegalStateException( "Table " + table.getName() + " never bound logically — register it via addTableNameBinding", e );
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Duplicate table mapping '{}'
- Named query definition is null
- Named query definition name is null: %s
- Duplicate named query '%s'
- Named native query definition object is null
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/eb370794f3b1c593.
Report an issue: GitHub.