hibernate/hibernate-orm · error · MappingException

Named native query [%s] specified both a resultset-ref and a

Error message

Named native query [%s] specified both a resultset-ref and an inline mapping of results

What it means

Hibernate binds each hbm.xml <sql-query> by folding its inline return elements (<return/>, <return-scalar/>, <return-join/>, <load-collection/>) into an implicit result-set mapping. A named native query may describe its results either through that inline mapping or by referencing a separately declared <resultset> via the resultset-ref attribute - never both. When at least one inline return exists and resultset-ref is also non-empty, NamedQueryBinder aborts bootstrap with this MappingException.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/NamedQueryBinder.java:146

					context
			);
			if ( wasQuery ) {
				foundQuery = true;
			}
		}
		if ( !foundQuery ) {
			throw new MappingException(
					"Named native query [%s] did not specify query string"
							.formatted( namedQueryBinding.getName() ),
					context.getOrigin()
			);
		}

		final var collector = context.getMetadataCollector();

		if ( implicitResultSetMappingBuilder.hasAnyReturns() ) {
			if ( isNotEmpty( namedQueryBinding.getResultsetRef() ) ) {
				throw new MappingException(
						"Named native query [%s] specified both a resultset-ref and an inline mapping of results"
								.formatted( namedQueryBinding.getName() ),
						context.getOrigin()
				);
			}

			collector.addResultSetMapping( implicitResultSetMappingBuilder.build( context ) );
			builder.setResultSetMappingName( implicitResultSetMappingBuilder.getRegistrationName() );
		}

		if ( namedQueryBinding.isCallable() ) {
			final var definition =
					createStoredProcedure( builder, context,
							() -> illegalCallSyntax( context, namedQueryBinding, builder.getSqlString() ) );
			collector.addNamedProcedureCallDefinition( definition );
			DEPRECATION_LOGGER.callableNamedNativeQuery();
		}
		else {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Choose one style: delete the resultset-ref attribute and keep the inline <return*> elements, or delete the inline elements and keep resultset-ref pointing at an existing <resultset name='personRs'> definition
  2. Verify the referenced <resultset> actually exists in the same document or an included one
  3. Validate the corrected file against the Hibernate hbm XSD to catch similar conflicting declarations

Example fix

// before - hbm.xml
<sql-query name='findAll' resultset-ref='personRs'>
    <return-scalar column='id'/>
    <return-scalar column='name'/>
</sql-query>

// after - inline mapping kept, resultset-ref removed
<sql-query name='findAll'>
    <return-scalar column='id'/>
    <return-scalar column='name'/>
</sql-query>
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight scan of every hbm.xml before building the SessionFactory
var doc = javax.xml.parsers.DocumentBuilderFactory.newInstance()
        .newDocumentBuilder().parse(hbmFile);
var queries = doc.getElementsByTagName("sql-query");
for (int i = 0; i < queries.getLength(); i++) {
    var q = (org.w3c.dom.Element) queries.item(i);
    boolean hasRef = !q.getAttribute("resultset-ref").isEmpty();
    boolean hasInline = q.getElementsByTagName("return").getLength() > 0
            || q.getElementsByTagName("return-scalar").getLength() > 0
            || q.getElementsByTagName("return-join").getLength() > 0
            || q.getElementsByTagName("load-collection").getLength() > 0;
    if (hasRef && hasInline)
        throw new IllegalStateException("sql-query '" + q.getAttribute("name")
                + "' mixes resultset-ref with inline returns");
}

Try / catch

try { Metadata metadata = metadataBuilder.build(); } catch (org.hibernate.boot.MappingException e) { /* message names the offending query; getOrigin() points at the hbm.xml source - surface both as a configuration error and stop startup */ throw new IllegalStateException("Bad native-query mapping: " + e.getMessage(), e); }

Prevention

When it happens

Trigger: An hbm.xml contains <sql-query name='findAll' resultset-ref='personRs'> that also declares at least one inline return child such as <return-scalar column='id'/> or <return alias='p' class='com.Person'/>. Thrown during Metadata building (SessionFactory bootstrap), before any query executes.

Common situations: Migrating between inline returns and shared named <resultset> definitions and leaving both halves in the file; merging two query definitions during copy-paste; hand-maintained legacy hbm.xml that never went through XSD validation.

Related errors


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