hibernate/hibernate-orm · error · DuplicateMappingException

Duplicate named stored procedure

Error message

Duplicate named stored procedure '{}'

What it means

DuplicateMappingException(Type.PROCEDURE): two named stored-procedure registrations use the same name in one persistence unit. The collector even inserts the second mapping before throwing, but the effect is identical — the SessionFactory build aborts. Procedure names share the global registration namespace per factory.

Solutions

  1. Search the project for the duplicated name from the message and rename one declaration
  2. Check persistence.xml for doubly-listed mapping files
  3. Namespace procedure names by feature (e.g. reporting.getDailyTotals) so independent modules cannot collide

Example fix

// before — both entities declare the same procedure name
@NamedStoredProcedureQuery(name = "syncUser", procedureName = "sync_user")
@NamedStoredProcedureQuery(name = "syncUser", procedureName = "sync_contact")

// after
@NamedStoredProcedureQuery(name = "User.sync", procedureName = "sync_user")
@NamedStoredProcedureQuery(name = "Contact.sync", procedureName = "sync_contact")
Defensive patterns

Strategy: validation

Validate before calling

static void assertNoDuplicateProcedureNames( Class<?>... entityClasses ) {
    final Set<String> seen = new HashSet<>();
    for ( final Class<?> c : entityClasses ) {
        for ( final NamedStoredProcedureQuery q : c.getAnnotationsByType( NamedStoredProcedureQuery.class ) ) {
            if ( !seen.add( q.name() ) ) {
                throw new IllegalStateException( "Duplicate @NamedStoredProcedureQuery name: " + q.name() );
            }
        }
    }
}

Try / catch

try {
    metadata.buildSessionFactory();
} catch ( DuplicateMappingException e ) {
    if ( e.getType() == DuplicateMappingException.Type.PROCEDURE ) {
        throw new IllegalStateException( "Duplicate named stored procedure '" + e.getName() + "' — rename one declaration", e );
    }
    throw e;
}

Prevention

When it happens

Trigger: Two @NamedStoredProcedureQuery(name="X") annotations; the same name declared via annotation in one module and orm.xml in another; a mapping file loaded twice.

Common situations: Copy-pasted stored-procedure annotations between entities, shared model jars defining the same procedure name, and copied orm.xml fragments that were never renamed.

Related errors


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

Appendix: source

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

		return namedProcedureCallMap.get( name );
	}

	@Override
	public void visitNamedProcedureCallDefinition(Consumer<NamedProcedureCallDefinition> definitionConsumer) {
		namedProcedureCallMap.values().forEach( definitionConsumer );
	}

	@Override
	public void addNamedProcedureCallDefinition(NamedProcedureCallDefinition definition) {
		if ( definition == null ) {
			throw new IllegalArgumentException( "Named query definition is null" );
		}
		else {
			final String name = definition.getRegistrationName();
			if ( !defaultNamedProcedureNames.contains( name ) ) {
				final var previous = namedProcedureCallMap.put( name, definition );
				if ( previous != null ) {
					throw new DuplicateMappingException( DuplicateMappingException.Type.PROCEDURE, name );
				}
			}
		}
	}

	@Override
	public void addDefaultNamedProcedureCall(NamedProcedureCallDefinitionImpl definition) {
		addNamedProcedureCallDefinition( definition );
		defaultNamedProcedureNames.add( definition.getRegistrationName() );
	}


	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// result-set mapping handling

	@Override
	public NamedResultSetMappingDescriptor getResultSetMapping(String name) {
		return sqlResultSetMappingMap.get( name );

View on GitHub (pinned to fad1729dce)