hibernate/hibernate-orm · error · IllegalArgumentException
Illegal attempt to treat 'java.sql.Date' as 'java.sql.Time'
Error message
Illegal attempt to treat 'java.sql.Date' as 'java.sql.Time'
What it means
JdbcDateJavaType is Hibernate's descriptor for DATE-precision values (java.sql.Date). Its unwrap() supports conversion to many targets (java.util.Date, Calendar, Timestamp, LocalDate), but it deliberately refuses java.sql.Time because turning a date-only value into a time-only value is not a meaningful conversion. The IllegalArgumentException fires whenever a code path (parameter binding, result extraction, dialect or user-type unwrap) asks Hibernate to convert a Date-precision value into java.sql.Time.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcDateJavaType.java:169
return type.cast( toDateEpoch( value ) );
}
if ( String.class.isAssignableFrom( type ) ) {
return type.cast( toString( value ) );
}
if ( Calendar.class.isAssignableFrom( type ) ) {
final var gregorianCalendar = new GregorianCalendar();
gregorianCalendar.setTimeInMillis( toDateEpoch( value ) );
return type.cast( gregorianCalendar );
}
if ( java.sql.Timestamp.class.isAssignableFrom( type ) ) {
return type.cast( new java.sql.Timestamp( toDateEpoch( value ) ) );
}
if ( java.sql.Time.class.isAssignableFrom( type ) ) {
throw new IllegalArgumentException( "Illegal attempt to treat 'java.sql.Date' as 'java.sql.Time'" );
}
throw unknownUnwrap( type );
}
private LocalDate unwrapLocalDate(java.util.Date value) {
return value instanceof java.sql.Date date
? date.toLocalDate()
: new java.sql.Date( toDateEpoch( value ) ).toLocalDate();
}
@Override
public @Nullable Date wrap(@Nullable Object value, WrapperOptions options) {
if ( value == null ) {
return null;
}
final var wrapped = wrapOrNull( value );
if ( wrapped == null ) {View on GitHub (pinned to fad1729dce)
Solutions
- Make the temporal precision consistent: use the same @Temporal value on the entity field and on every query.setParameter(...) call for that attribute
- Replace legacy java.util.Date/java.sql.* fields with java.time types (LocalDate, LocalTime, LocalDateTime) - Hibernate 6 maps these precisely and this class of cross-unwrap cannot happen
- If you really need a Time from a Date value, convert it yourself (new java.sql.Time(date.getTime())) instead of relying on Hibernate's unwrap
- Audit custom UserType/AttributeConverter implementations for unwrap() calls that request java.sql.Time.class while handling date values
Example fix
// before
@Temporal(TemporalType.DATE)
private java.util.Date birthDate;
...
query.setParameter("p", entity.getBirthDate(), TemporalType.TIME); // IllegalArgumentException
// after
@Temporal(TemporalType.DATE)
private java.util.Date birthDate;
...
query.setParameter("p", entity.getBirthDate(), TemporalType.DATE);
// better: private LocalDate birthDate; and no @Temporal at all Defensive patterns
Strategy: type-guard
Validate before calling
if (value instanceof java.sql.Date && !(value instanceof java.sql.Timestamp)) {
// DATE-precision value: bind only with TemporalType.DATE, never TemporalType.TIME
} Type guard
static boolean isDatePrecision(Object v) {
return v instanceof java.util.Date && !(v instanceof java.sql.Time);
} Try / catch
try {
query.setParameter("p", value, TemporalType.DATE);
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Temporal precision mismatch between field and parameter: " + e.getMessage(), e);
} Prevention
- Use java.time types (LocalDate/LocalTime/LocalDateTime) for all new mappings
- Keep @Temporal identical on the entity field and every parameter binding
- Never bind a java.sql.Date value to a TIME parameter or vice versa
When it happens
Trigger: unwrap(date, java.sql.Time.class, options) is reached when: an entity attribute or query parameter is bound with @Temporal(TemporalType.TIME) while the value is managed by the DATE descriptor (e.g. query.setParameter(name, javaSqlDateValue, TemporalType.TIME)); a java.sql.Date value is bound to a parameter whose JavaType is JdbcTimeJavaType; or a custom UserType/AttributeConverter calls unwrap with java.sql.Date/Time.class on the wrong descriptor.
Common situations: Mixing legacy java.util.Date/java.sql.Date field types with TIME-precision parameters; porting code from Hibernate 5 to 6 where temporal descriptor resolution became stricter; entity fields declared java.util.Date with @Temporal(TemporalType.DATE) but queried with a different TemporalType.
Related errors
- Illegal attempt to treat `java.sql.Time` as `java.sql.Date`
- Unknown unwrap conversion requested: " + type.getTypeName()
- Unwrap strategy not known for this Java type: " + getTypeNam
- field type not supported on Derby: " + unit
- field type not supported on Derby: " + unit
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/e1509ed6c0a7a210.
Report an issue: GitHub.