hibernate/hibernate-orm · error · QueryException

Unsupported enum type passed to 'ordinal()' function: %s

Error message

Unsupported enum type passed to 'ordinal()' function: %s

What it means

The HQL ordinal() function converts a name-mapped enum to its ordinal by rendering a CASE expression over the enum constants' names, converting each name with the attribute's single JDBC mapping. This is only implementable when the mapping can turn an enum name into its relational (string) value; any other argument type — ORDINAL-mapped enum (the JPA default), an enum behind an AttributeConverter, or a non-enum expression — throws QueryException at render time.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/dialect/function/OrdinalFunction.java:82

		else if ( argumentType.isString() || argumentType.getDefaultSqlTypeCode() == SqlTypes.ENUM ) {

			EnumJavaType<?> enumJavaType = (EnumJavaType<?>) singleJdbcMapping.getMappedJavaType();
			Object[] enumConstants = enumJavaType.getJavaTypeClass().getEnumConstants();

			sqlAppender.appendSql( "case " );
			singleExpression.accept( walker );
			for ( Object e : enumConstants ) {
				Enum<?> enumValue = (Enum<?>) e;
				sqlAppender.appendSql( " when " );
				sqlAppender.appendSingleQuoteEscapedString( (String) singleJdbcMapping.convertToRelationalValue(
						enumValue.toString() ) );
				sqlAppender.appendSql( " then " );
				sqlAppender.appendSql( enumValue.ordinal() );
			}
			sqlAppender.appendSql( " end" );
		}
		else {
			throw new QueryException( "Unsupported enum type passed to 'ordinal()' function: " + argumentType );
		}
	}

	@Override
	public String getArgumentListSignature() {
		return "(ENUM arg)";
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Annotate the attribute @Enumerated(EnumType.STRING) so the CASE rendering works
  2. If the enum is already ORDINAL-mapped, drop ordinal() — the column already holds the ordinal value
  3. Remove the AttributeConverter/custom JdbcType from that attribute or make it name-based
  4. Upgrade Hibernate for widened ordinal() support across mappings

Example fix

// before
@Enumerated          // defaults to ORDINAL -> ordinal(e.status) throws
private Status status;

// after
@Enumerated(EnumType.STRING)
private Status status;
Defensive patterns

Strategy: type-guard

Validate before calling

// Before exposing ordinal() in HQL templates, verify the attribute is STRING-mapped
static boolean isStringMappedEnum(Class<?> entity, String field) throws Exception {
    Enumerated e = entity.getDeclaredField(field).getAnnotation(Enumerated.class);
    return e != null && e.value() == EnumType.STRING;
}

Type guard

static boolean supportsOrdinalHql(Class<?> entity, String field) throws Exception {
    Class<?> type = entity.getDeclaredField(field).getType();
    if (!type.isEnum()) return false;
    Enumerated e = entity.getDeclaredField(field).getAnnotation(Enumerated.class);
    return e != null && e.value() == EnumType.STRING;
}

Try / catch

try {
    return em.createQuery("select ordinal(e.status) from E e", Integer.class).getResultList();
} catch (org.hibernate.QueryException e) {
    if (e.getMessage() != null && e.getMessage().contains("ordinal()")) {
        throw new QuerySetupException("ordinal() requires a STRING-mapped enum attribute", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: HQL: select ordinal(e.status) from MyEntity e where status is @Enumerated(ORDINAL) (or has no @Enumerated at all), uses a converter/custom JdbcType, or the argument is not an enum attribute.

Common situations: Calling ordinal() on enums left at the JPA default mapping; entities retrofitted with AttributeConverters; assuming ordinal() is a generic enum-to-int function for every mapping style.

Related errors


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