quarkusio/quarkus · error · RuntimeException

Unable to handle temporal type '${paramType}'

Error message

Unable to handle temporal type '${paramType}'

What it means

determineTemporalConverter maps a fixed set of java.time types (LocalDate, LocalDateTime, LocalTime, OffsetDateTime, OffsetTime, ZonedDateTime, YearMonth, Period, Instant) to built-in param converters. Any other type (Duration, ZoneId, Month, java.util.Date, custom temporals) fails deployment with this RuntimeException.

Source

Thrown at independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java:655

        } else if (LOCAL_DATE_TIME.equals(paramType)) {
            return new LocalDateTimeParamConverter.Supplier(format, dateTimeFormatterProviderClassName);
        } else if (LOCAL_TIME.equals(paramType)) {
            return new LocalTimeParamConverter.Supplier(format, dateTimeFormatterProviderClassName);
        } else if (OFFSET_DATE_TIME.equals(paramType)) {
            return new OffsetDateTimeParamConverter.Supplier(format, dateTimeFormatterProviderClassName);
        } else if (OFFSET_TIME.equals(paramType)) {
            return new OffsetTimeParamConverter.Supplier(format, dateTimeFormatterProviderClassName);
        } else if (ZONED_DATE_TIME.equals(paramType)) {
            return new ZonedDateTimeParamConverter.Supplier(format, dateTimeFormatterProviderClassName);
        } else if (YEAR.equals(paramType)) {
            return new YearParamConverter.Supplier(format, dateTimeFormatterProviderClassName);
        } else if (YEAR_MONTH.equals(paramType)) {
            return new YearMonthParamConverter.Supplier(format, dateTimeFormatterProviderClassName);
        } else if (PERIOD.equals(paramType)) {
            return new PeriodParamConverter.Supplier();
        }

        throw new RuntimeException(
                contextualizeErrorMessage("Unable to handle temporal type '" + paramType + "'", currentMethodInfo));
    }

    private void validateMethodsForInjectableBean(ClassInfo currentClassInfo) {
        // do not check methods of records, they get the annotations from their record components, but that's automatic:
        // they are actually placed on the constructor parameters and also end up on the fields and methods
        if (currentClassInfo.isRecord()) {
            return;
        }
        for (MethodInfo method : currentClassInfo.methods()) {
            for (AnnotationInstance annotation : method.annotations()) {
                if (annotation.target().kind() == AnnotationTarget.Kind.METHOD) {
                    for (DotName annotationForField : JAX_RS_ANNOTATIONS_FOR_FIELDS) {
                        if (annotation.name().equals(annotationForField)) {
                            throw new DeploymentException(String.format(
                                    "Method '%s' of class '%s' is annotated with @%s annotation which is prohibited. "
                                            + "Classes used as @BeanParam parameters must have a JAX-RS parameter annotation on "
                                            + "fields only.",

View on GitHub (pinned to e1c734241f)

Solutions

  1. Change the parameter to a supported temporal type (LocalDate, LocalDateTime, LocalTime, OffsetDateTime, OffsetTime, ZonedDateTime, YearMonth, Period, Instant).
  2. For Duration-like types, accept String and parse manually (Duration.parse) or register a custom ParamConverter.
  3. Compare the paramType in the message against the supported branches in ServerEndpointIndexer.

Example fix

// before
@QueryParam("ttl")
@DateFormat(format = "HH:mm")
Duration ttl;

// after
@QueryParam("ttl")
String ttl; // then Duration.parse(ttl) in the handler
Defensive patterns

Strategy: type-guard

Validate before calling

static final Set<Class<?>> SUPPORTED_TEMPORAL = Set.of(
    LocalDate.class, LocalDateTime.class, LocalTime.class, OffsetDateTime.class,
    OffsetTime.class, ZonedDateTime.class, YearMonth.class, Period.class,
    java.time.Instant.class);
static boolean isSupportedTemporal(Class<?> t) { return SUPPORTED_TEMPORAL.contains(t); }

Try / catch

try {
    startQuarkus();
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Unable to handle temporal type")) {
        log.error("Switch to a supported java.time type: " + e.getMessage());
    } else { throw e; }
}

Prevention

When it happens

Trigger: A temporal/convert position parameter of an unsupported type, e.g. @QueryParam("ttl") Duration ttl or @QueryParam("month") Month month where no converter branch matches.

Common situations: Assuming all java.time types are supported; migrating from frameworks where Duration-style query params worked; using java.util.Date where the reactive stack expects temporal types.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/1ceb9b4a88af5ee1. Report an issue: GitHub.