hibernate/hibernate-orm · error · IllegalArgumentException
Invalid temporal field [{}]
Error message
Invalid temporal field [{}] What it means
The criteria overload extract(TemporalField, Expression) maps the field to a TemporalUnit via a switch over field.toString(); only a fixed set of names is recognized (year, quarter, month, week, day, hour, minute, second, date, time per the surrounding switch). Any other string form — a custom enum constant, a typo, or fields Hibernate's switch doesn't cover — hits default and throws IllegalArgumentException.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java:3743
temporalUnit = TemporalUnit.HOUR;
break;
case "minute":
temporalUnit = TemporalUnit.MINUTE;
break;
case "second":
temporalUnit = TemporalUnit.SECOND;
resultType = Double.class;
break;
case "date":
temporalUnit = TemporalUnit.DATE;
resultType = LocalDate.class;
break;
case "time":
temporalUnit = TemporalUnit.TIME;
resultType = LocalTime.class;
break;
default:
throw new IllegalArgumentException( "Invalid temporal field [" + field + "]" );
}
//noinspection unchecked
return extract( temporal, temporalUnit, (Class<N>) resultType );
}
private <T> SqmFunction<T> extract(
Expression<? extends TemporalAccessor> datetime,
TemporalUnit temporalUnit,
Class<T> type) {
return getFunctionDescriptor( "extract" ).generateSqmExpression(
asList(
new SqmExtractUnit<>(
temporalUnit,
getTypeConfiguration().standardBasicTypeForJavaType( type ),
this
),
(SqmTypedNode<?>) datetime
),View on GitHub (pinned to fad1729dce)
Solutions
- Use the unit-based overload: cb.extract(TemporalUnit.YEAR, ts) with org.hibernate.query.TemporalUnit, which has no string switch.
- If you keep the TemporalField overload, make your enum's toString() return one of the recognized names exactly (lowercase: year, quarter, month, week, day, hour, minute, second, date, time).
- Map your public API field names to the supported names before calling extract.
Example fix
// before
enum F { ISO_YEAR } // toString() = "ISO_YEAR"
cb.extract(F.ISO_YEAR, ts); // Invalid temporal field [ISO_YEAR]
// after
import org.hibernate.query.TemporalUnit;
cb.extract(TemporalUnit.YEAR, ts); Defensive patterns
Strategy: validation
Validate before calling
private static final Set<String> SUPPORTED = Set.of(
"year", "quarter", "month", "week", "day",
"hour", "minute", "second", "date", "time");
boolean supported(String field) { return SUPPORTED.contains(field.toLowerCase(Locale.ROOT)); }
if (!supported(field.toString())) throw new IllegalArgumentException("Unsupported temporal field: " + field); Type guard
static boolean extractFieldSupported(TemporalField f) {
return Set.of("year","quarter","month","week","day","hour","minute","second","date","time")
.contains(f.toString());
} Try / catch
try {
e = cb.extract(field, ts);
} catch (IllegalArgumentException ex) {
if (ex.getMessage().contains("Invalid temporal field")) e = cb.extract(TemporalUnit.YEAR, ts);
else throw ex;
} Prevention
- Prefer the TemporalUnit-based extract overload — no string switch involved.
- If you own the TemporalField enum, make toString() return the exact lowercase names Hibernate recognizes.
- Map external field names through a whitelist before calling extract.
When it happens
Trigger: cb.extract(TemporalField.YEAR, ts) where TemporalField is a user-defined enum whose constant prints differently (e.g. 'Year' or 'YEAR_OF_ERA'); passing java.time.temporal.ChronoField constants not handled by the switch; typos in string-based field selection.
Common situations: Defining your own TemporalField-like enum for a query DSL and forwarding its constants; assuming every java.time.temporal.ChronoField is supported; upgrading Hibernate versions where the accepted-field switch changed.
Related errors
- field type not supported on Derby: " + unit
- field type not supported on Derby: " + unit
- Argument '%s' of 'fk()' function is not a single-valued asso
- Unrecognized field:
- Informix does not support binary literals
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/a75f90c51a087e6c.
Report an issue: GitHub.