hibernate/hibernate-orm · error · DuplicateMappingException

Table [%s] contains physical column name [%s] referred to by

Error message

Table [%s] contains physical column name [%s] referred to by multiple logical column names: [%s], [%s]

What it means

The mirror check of the logical-to-physical one: one physical column of a table was registered under a second, different logical name (Identifier equality is exact, so case or quoting differences count as different names). Because reverse resolution would be ambiguous, Hibernate throws DuplicateMappingException(Type.COLUMN_BINDING) and aborts bootstrap.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java:1102

									Locale.ENGLISH,
									"Table [%s] contains logical column name [%s] referring to multiple physical " +
											"column names: [%s], [%s]",
									tableName,
									logicalName,
									existingPhysicalNameMapping,
									physicalName
							),
							DuplicateMappingException.Type.COLUMN_BINDING,
							tableName + "." + logicalName
					);
				}
			}
		}

		private void bindPhysicalToLogical(Identifier logicalName, String physicalName) throws DuplicateMappingException {
			final Identifier existingLogicalName = physicalToLogical.put( physicalName, logicalName );
			if ( existingLogicalName != null && ! existingLogicalName.equals( logicalName ) ) {
				throw new DuplicateMappingException(
						String.format(
								Locale.ENGLISH,
								"Table [%s] contains physical column name [%s] referred to by multiple logical " +
										"column names: [%s], [%s]",
								tableName,
								physicalName,
								logicalName,
								existingLogicalName
						),
						DuplicateMappingException.Type.COLUMN_BINDING,
						tableName + "." + physicalName
				);
			}
		}
	}

	private Map<Table,TableColumnNameBinding> columnNameBindingByTableMap;

View on GitHub (pinned to fad1729dce)

Solutions

  1. Give the column a single owning mapping and drop the redundant property, or mark the extra one insertable=false, updatable=false
  2. Where two mappings must coexist, align their logical names exactly (same spelling and quoting)
  3. Use @AssociationOverride/@AttributeOverride to bind embeddables to columns not otherwise mapped in that table
  4. Search the entity named in the message for duplicate name= values across @Column and @JoinColumn

Example fix

// before: FK column mapped twice under different logical names
@ManyToOne
@JoinColumn(name = "dept_id")
private Department department;

@Column(name = "dept_id")
private Long deptId;

// after: one owner; the read-only copy is non-insertable/non-updatable
@ManyToOne
@JoinColumn(name = "dept_id")
private Department department;

@Column(name = "dept_id", insertable = false, updatable = false)
private Long deptId;
Defensive patterns

Strategy: try-catch

Validate before calling

static void assertNoRepeatedColumns( Class<?> entity ) {
    final Map<String, String> columnOwner = new HashMap<>();
    for ( Class<?> c = entity; c != null && c != Object.class; c = c.getSuperclass() ) {
        for ( final Field f : c.getDeclaredFields() ) {
            final Column col = f.getAnnotation( Column.class );
            final JoinColumn join = f.getAnnotation( JoinColumn.class );
            final String name = col != null ? col.name() : ( join != null ? join.name() : null );
            if ( name != null && !name.isEmpty() ) {
                final String prev = columnOwner.put( name.toLowerCase( Locale.ROOT ), f.getName() );
                if ( prev != null ) {
                    throw new IllegalStateException( "Column '" + name + "' mapped by both '" + prev + "' and '" + f.getName() + "'" );
                }
            }
        }
    }
}

Try / catch

try {
    sessionFactory = metadata.buildSessionFactory();
} catch ( DuplicateMappingException e ) {
    if ( e.getType() == DuplicateMappingException.Type.COLUMN_BINDING
            && e.getMessage() != null && e.getMessage().contains( "multiple logical" ) ) {
        // one physical column referenced under two different logical names in the named table
        throw new IllegalStateException( "Repeated column mapping: " + e.getMessage(), e );
    }
    throw e;
}

Prevention

When it happens

Trigger: Two properties of one entity mapped to the same physical column under different logical names — a @JoinColumn(name="dept_id") association plus a basic @Column(name="dept_id") field; an embeddable overridden onto a column the owner already maps; logical names differing only in case.

Common situations: The classic JPA 'repeated column' setup where a foreign key is exposed both as an association and as a plain field, legacy schemas mapped by multiple teams, and attribute renames that kept the old column mapping as a duplicate.

Related errors


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