hibernate/hibernate-orm · error · IllegalArgumentException

Unsure how to handle given Java type [{}] as TemporalType#TI

Error message

Unsure how to handle given Java type [{}] as TemporalType#TIMESTAMP

What it means

When a parameter is bound with TemporalType.TIMESTAMP, BindingTypeHelper.resolveTimestampTemporalTypeVariant maps the parameter's Java type to a TIMESTAMP-capable basic type (BindingTypeHelper.java:123-146). It handles java.util.Date, Calendar, LocalDateTime, Instant, OffsetDateTime, ZonedDateTime and OffsetTime; any other class falls through to this IllegalArgumentException naming the unsupported Java type.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/type/internal/BindingTypeHelper.java:143

			return typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.CALENDAR );
		}
		else if ( java.util.Date.class.isAssignableFrom( javaType ) ) {
			return typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.TIMESTAMP );
		}
		else if ( Instant.class.isAssignableFrom( javaType ) ) {
			return typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.INSTANT );
		}
		else if ( OffsetDateTime.class.isAssignableFrom( javaType ) ) {
			return typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.OFFSET_DATE_TIME );
		}
		else if ( ZonedDateTime.class.isAssignableFrom( javaType ) ) {
			return typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.ZONED_DATE_TIME );
		}
		else if ( OffsetTime.class.isAssignableFrom( javaType ) ) {
			return typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.OFFSET_TIME );
		}
		else {
			throw new IllegalArgumentException( "Unsure how to handle given Java type ["
												+ javaType.getName() + "] as TemporalType#TIMESTAMP" );
		}
	}

	private static BindableType<?> resolveDateTemporalTypeVariant(
			Class<?> javaType,
			BindableType<?> baseType,
			TypeConfiguration typeConfiguration) {
		if ( baseType.getJavaType().isAssignableFrom( javaType ) ) {
			return baseType;
		}
		else if ( Calendar.class.isAssignableFrom( javaType ) ) {
			return typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.CALENDAR_DATE );
		}
		else if ( java.util.Date.class.isAssignableFrom( javaType ) ) {
			return typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.DATE );
		}
		else if ( Instant.class.isAssignableFrom( javaType ) ) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Drop the TemporalType argument entirely - Hibernate already maps LocalDate/LocalTime/LocalDateTime correctly without it.
  2. Use TemporalType.DATE for LocalDate, TemporalType.TIME for LocalTime, and reserve TemporalType.TIMESTAMP for LocalDateTime/Instant/OffsetDateTime/ZonedDateTime/Date/Calendar.
  3. Convert the value: value.atStartOfDay() for LocalDate, value.atDate(...) for LocalTime, before binding with TIMESTAMP precision.

Example fix

// before - LocalDate cannot be bound as TIMESTAMP
query.setParameter("ts", LocalDate.now(), TemporalType.TIMESTAMP);

// after - either let Hibernate infer
query.setParameter("ts", LocalDate.now());
// or convert to a TIMESTAMP-capable type
query.setParameter("ts", LocalDate.now().atStartOfDay());
Defensive patterns

Strategy: type-guard

Validate before calling

static final Set<Class<?>> TIMESTAMP_OK = Set.of(
    java.util.Date.class, java.util.Calendar.class,
    java.time.LocalDateTime.class, java.time.Instant.class,
    java.time.OffsetDateTime.class, java.time.ZonedDateTime.class,
    java.time.OffsetTime.class );

if ( !TIMESTAMP_OK.contains( value.getClass() ) ) {
    throw new IllegalArgumentException( "Bind " + value.getClass().getSimpleName()
        + " without TemporalType, or convert to a timestamp-capable type" );
}

Type guard

static boolean supportsTimestampPrecision(Object v) {
    return v instanceof java.util.Date || v instanceof java.util.Calendar
        || v instanceof java.time.LocalDateTime || v instanceof java.time.Instant
        || v instanceof java.time.OffsetDateTime || v instanceof java.time.ZonedDateTime
        || v instanceof java.time.OffsetTime;
}

Prevention

When it happens

Trigger: Query.setParameter('ts', LocalDate.now(), TemporalType.TIMESTAMP) - LocalDate has no TIMESTAMP variant; passing LocalTime, YearMonth, java.sql.Date subclasses outside the handled set, or a custom temporal-ish class with TemporalType.TIMESTAMP; stored-procedure parameters bound the same way.

Common situations: Migrating fields from java.util.Date to java.time types while keeping old TemporalType.TIMESTAMP arguments; code written for one temporal family (LocalDate) reused with precision meant for another (TIMESTAMP).

Related errors


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