quarkusio/quarkus · error · RuntimeException

Could not create converter for ${elementType} for ${builder.

Error message

Could not create converter for ${elementType} for ${builder.getErrorLocation()} of type ${builder.getType()}

What it means

For simple indexed parameters (@QueryParam, @HeaderParam, etc.), handleOtherParam builds a runtime converter via extractConverter. If converter creation fails for any reason (unsupported type, no ParamConverter, no String factory), the Throwable is wrapped in this RuntimeException naming the element type, error location, and parameter type.

Source

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

        if (SUPPORTED_MULTIPART_FILE_TYPES.contains(DotName.createSimple(declaredType))) {
            fileFormNames.add(name);
        }
        return new ServerMethodParameter(name,
                elementType, declaredType, declaredTypes.getDeclaredUnresolvedType(),
                type, single, signature,
                converter, defaultValue, parameterResult.isObtainedAsCollection(), parameterResult.isOptional(), encoded,
                parameterResult.getCustomParameterExtractor(), mimeType, parameterResult.getSeparator());
    }

    @Override
    protected void handleOtherParam(Map<String, String> existingConverters, String errorLocation, boolean hasRuntimeConverters,
            ServerIndexedParameter builder, String elementType, MethodInfo currentMethodInfo) {
        try {
            builder.setConverter(extractConverter(elementType, index,
                    existingConverters, errorLocation, hasRuntimeConverters, builder.getAnns(), currentMethodInfo));
        } catch (Throwable throwable) {
            throw new RuntimeException("Could not create converter for " + elementType + " for " + builder.getErrorLocation()
                    + " of type " + builder.getType(), throwable);
        }
    }

    @Override
    protected void handleSortedSetParam(Map<String, String> existingConverters, String errorLocation,
            boolean hasRuntimeConverters, ServerIndexedParameter builder, String elementType, MethodInfo currentMethodInfo) {
        ParameterConverterSupplier converter = extractConverter(elementType, index,
                existingConverters, errorLocation, hasRuntimeConverters, builder.getAnns(), currentMethodInfo);
        builder.setConverter(new SortedSetConverter.SortedSetSupplier(converter));
    }

    @Override
    protected void handleOptionalParam(Map<String, String> existingConverters,
            Map<DotName, AnnotationInstance> parameterAnnotations,
            String errorLocation,
            boolean hasRuntimeConverters, ServerIndexedParameter builder, String elementType, String genericElementType,
            MethodInfo currentMethodInfo) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Change the parameter to a convertible type (String, primitive, wrapper, enum, or a type with public static valueOf/of/fromString(String)) or register a ParamConverter/ParamConverterProvider.
  2. Inspect the wrapped cause attached to this RuntimeException — it names the exact failure.
  3. Upgrade Quarkus if the type should be built-in supported.
  4. Accept String and parse manually as a last resort.

Example fix

// before
@QueryParam("range")
Range range; // custom type, no converter

// after
@QueryParam("range")
String range; // parse manually, or register a ParamConverter for Range
Defensive patterns

Strategy: type-guard

Validate before calling

static boolean isConvertibleParamType(Class<?> t) {
    if (t == String.class || t.isPrimitive()) return true;
    if (t.isEnum()) return true;
    for (String m : new String[]{"valueOf", "of", "from", "fromString", "parse"}) {
        try { t.getMethod(m, String.class); return true; } catch (NoSuchMethodException ignored) {}
    }
    return false;
}

Type guard

static boolean hasStringFactory(Class<?> t) {
    return java.util.Arrays.stream(t.getMethods()).anyMatch(m ->
        java.lang.reflect.Modifier.isStatic(m.getModifiers())
        && m.getParameterCount() == 1 && m.getParameterTypes()[0] == String.class
        && t.isAssignableFrom(m.getReturnType()));
}

Try / catch

try {
    deploymentResult = quarkusBuild();
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Could not create converter for")) {
        log.error("Register a ParamConverter or change the param type: " + e.getMessage(), e.getCause());
    } else { throw e; }
}

Prevention

When it happens

Trigger: Declaring @QueryParam("ids") List<SomePojo> ids, or a raw/custom type with no registered ParamConverter and no valueOf/of/fromString(String) factory.

Common situations: Using entity/DTO classes as query/header params; custom types that worked under classic RESTEasy but lack reactive converters; enums refactored without valueOf-compatible factories.

Related errors


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