hibernate/hibernate-orm · error · QueryException

Unknown placeholder {token}

Error message

Unknown placeholder {token}

What it means

Legacy native queries support '{...}' interpolation. SQLQueryParser recognizes only built-in keywords {h-schema} and {h-catalog} plus alias-bound tokens like {alias.prop} and {alias.*} resolved against declared returns. Any other token between braces reaches the default branch and throws QueryException("Unknown placeholder", token).

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sql/internal/SQLQueryParser.java:215

				if ( defaultSchema != null ) {
					result.append( defaultSchema.render(dialect) );
					result.append( "." );
				}
				break;
			case "h-schema":
				if ( defaultSchema != null ) {
					result.append( defaultSchema.render(dialect) );
					result.append( "." );
				}
				break;
			case "h-catalog":
				if ( defaultCatalog != null ) {
					result.append( defaultCatalog.render(dialect) );
					result.append( "." );
				}
				break;
			default:
				throw new QueryException( "Unknown placeholder ", token);
		}
	}

	private String resolveCollectionProperties(String aliasName, String propertyName, String token) {
		final var fieldResults = context.getPropertyResultsMap( aliasName );
		final var collectionPersister = context.getCollectionPersister( aliasName );
		final String collectionSuffix = context.getCollectionSuffix( aliasName );
		switch ( propertyName ) {
			case "*":
				if ( !fieldResults.isEmpty() ) {
					throw new QueryException(
							"Illegal interpolation '%s' ('%s' is a field alias)"
									.formatted( token, aliasName ),
							originalQueryString
					);
				}
				aliasesFound++;
				return collectionPersister.selectFragment( aliasName, collectionSuffix )

View on GitHub (pinned to fad1729dce)

Solutions

  1. Use the supported built-ins: {h-schema} renders the default schema (append '.'), {h-catalog} the default catalog.
  2. Remove the braces and inline the value yourself, or keep templating outside Hibernate and pass the finished SQL string in.
  3. If the token was meant to be an alias interpolation, declare the alias (addEntity/addScalar/addJoin) with that exact name or fix the typo.

Example fix

-- before
select * from {schema}users where ...

-- after
select * from {h-schema}users where ...
Defensive patterns

Strategy: validation

Validate before calling

static final java.util.Set<String> BUILTIN_PLACEHOLDERS = java.util.Set.of("h-schema", "h-catalog");
static void validatePlaceholders(String sql, java.util.Set<String> declaredAliases) {
    var m = java.util.regex.Pattern.compile("\\{([A-Za-z_][\\w-]*)(?:[.*]|\\})").matcher(sql);
    while (m.find()) {
        String head = m.group(1);
        if (!BUILTIN_PLACEHOLDERS.contains(head) && !declaredAliases.contains(head))
            throw new IllegalArgumentException("Unknown placeholder {" + head + "} in native query");
    }
}

Try / catch

try { query.list(); } catch (org.hibernate.QueryException e) { /* if 'Unknown placeholder', replace {token} with {h-schema}/{h-catalog} or the declared alias form */ throw e; }

Prevention

When it happens

Trigger: Native SQL containing e.g. {schema}, {catalog}, {tenant}, or a mistyped {h-schame}, none of which are keywords or declared return aliases. Fires when the query string is parsed/expanded, i.e. when the query is prepared for execution.

Common situations: Teams assuming arbitrary template variables are supported inside braces; typos in {h-schema}; custom placeholder syntax from in-house query templates leaking into Hibernate-managed native queries; migration from very old Hibernate where extra placeholders were interpolated by hand.

Related errors


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