hibernate/hibernate-orm · error · MappingException

No column with logical name '{}' in table '{}'

Error message

No column with logical name '{}' in table '{}'

What it means

Hibernate resolves column names through a two-level model: each mapped column registers a LOGICAL name, and physical names are derived later by the naming strategy. Here getPhysicalColumnName(table, logicalReferencedColumnName) found no registered logical column with that name in the given table, and the helper rethrows a plain MappingException. It usually means the name you passed is the physical/database name, or the logical registration differs from what the mapping assumes.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumns.java:401

	private static Table table(Object persistentClassOrJoin) {
		if ( persistentClassOrJoin instanceof PersistentClass persistentClass ) {
			return persistentClass.getTable();
		}
		else if ( persistentClassOrJoin instanceof Join join ) {
			return join.getTable();
		}
		else {
			throw new IllegalArgumentException( "Unexpected object" );
		}
	}

	private static Column column(MetadataBuildingContext context, Table table, String logicalReferencedColumnName) {
		try {
			return new Column( context.getMetadataCollector()
					.getPhysicalColumnName( table, logicalReferencedColumnName ) );
		}
		catch ( MappingException me ) {
			throw new MappingException( "No column with logical name '" + logicalReferencedColumnName
					+ "' in table '" + table.getName() + "'" );
		}
	}

	String buildDefaultColumnName(PersistentClass referencedEntity, String logicalReferencedColumn) {
		final var context = getBuildingContext();
		final var options = context.getBuildingOptions();
		final var collector = context.getMetadataCollector();
		final var database = collector.getDatabase();
		final var jdbcEnvironment = database.getJdbcEnvironment();
		final Identifier columnIdentifier = columnIdentifier(
				referencedEntity,
				logicalReferencedColumn,
				options.getImplicitNamingStrategy(),
				collector,
				database
		);
		return options.getPhysicalNamingStrategy()

View on GitHub (pinned to fad1729dce)

Solutions

  1. Use the LOGICAL (pre-strategy, as-written-in-mapping) name in referencedColumnName/ordering references, not the transformed physical name.
  2. Check your ImplicitNamingStrategy/PhysicalNamingStrategy beans: reproduce the transformation to see what logical name the target column was registered under.
  3. Search for duplicate mappings of the table named in the message and consolidate them.

Example fix

// before
// DB column is CUST_NO; entity maps @Column(name = "CUST_NO")
@JoinColumn(name = "customer_no", referencedColumnName = "cust_no") // physical name -> resolution fails

// after
@JoinColumn(name = "customer_no", referencedColumnName = "CUST_NO") // exactly the mapped @Column name
Defensive patterns

Strategy: validation

Validate before calling

// Guard: referenced names must equal the LOGICAL name as written in @Column
String referenced = "cust_no";
boolean matches = Arrays.stream(Target.class.getDeclaredFields())
    .map(f -> { Column c = f.getAnnotation(Column.class);
                return c == null || c.name().isEmpty() ? f.getName() : c.name(); })
    .anyMatch(referenced::equals);
if (!matches) throw new IllegalStateException(
    "'" + referenced + "' is not a logical column name of " + Target.class.getName());

Try / catch

try {
    Metadata md = sources.buildMetadata();
} catch (MappingException e) {
    // 'No column with logical name ... in table ...' -> referenced name differs from
    // the logical name; fix it or check the naming strategy transformation
    throw newConfigurationException("Logical column name mismatch", e);
}

Prevention

When it happens

Trigger: referencedColumnName or ordering logic supplies a physical name produced by a custom PhysicalNamingStrategy/ImplicitNamingStrategy that differs from the logical name; two mappings claim the same table with different logical names; referencing a column of a table mapped through a @Formula or secondary table where no logical name was registered.

Common situations: Custom naming strategies (snake_case conversions, prefixing) applied after mappings were written with physical names; entity A joining to a column of entity B by its DB name while B registered the logical Java-derived name; duplicate/conflicting mappings of one table across entities or XML + annotations.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/0276444f62726d49. Report an issue: GitHub.