quarkusio/quarkus · error · IllegalArgumentException

Type + type.name().toString() + which is used in class +

Error message

Type  + type.name().toString() +  which is used in class  + declaringClass +  must define a single generic argument

What it means

Companion check in determineSingleGenericType: the type IS parameterized but declares more than one generic argument. Types used in this position must have exactly one type argument, otherwise IllegalArgumentException '... must define a single generic argument' is thrown.

Source

Thrown at extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/ConfigurationPropertiesUtil.java:194

        return DotNames.COLLECTION.equals(resultType.name()) ||
                DotNames.LIST.equals(resultType.name()) ||
                DotNames.SET.equals(resultType.name());
    }

    private static boolean isMap(final Type resultType) {
        return DotNames.MAP.equals(resultType.name()) ||
                DotNames.HASH_MAP.equals(resultType.name());
    }

    static Type determineSingleGenericType(Type type, DotName declaringClass) {
        if (!(type.kind() == Type.Kind.PARAMETERIZED_TYPE)) {
            throw new IllegalArgumentException("Type " + type.name().toString() + " which is used in class " + declaringClass
                    + " must define a generic argument");
        }

        ParameterizedType parameterizedType = type.asParameterizedType();
        if (parameterizedType.arguments().size() != 1) {
            throw new IllegalArgumentException("Type " + type.name().toString() + " which is used in class " + declaringClass
                    + " must define a single generic argument");
        }

        return type.asParameterizedType().arguments().get(0);
    }

    static void registerImplicitConverter(Type type, BuildProducer<ReflectiveClassBuildItem> reflectiveClasses) {
        // We need to register for reflection in case an implicit converter is required.
        if (!MicroProfileConfigProcessor.isHandledByProducers(type)) {
            if (type.kind() != Type.Kind.ARRAY) {
                reflectiveClasses
                        .produce(ReflectiveClassBuildItem.builder(type.name().toString()).methods().build());
            }
        }
    }
}

View on GitHub (pinned to e1c734241f)

Solutions

  1. Use single-argument types (List<T>, Optional<T>, Set<T>) for such properties; handle Maps via the dedicated Map path with parameterized Map<K, V>.
  2. Split multi-argument types into simpler properties.
  3. Review which container type the getter returns and align it with the supported set.

Example fix

// before
Pair<String, Integer> getRange();

// after
List<Integer> getRange(); // or a supported single-arg type
Defensive patterns

Strategy: type-guard

Type guard

static boolean isSingleArgContainer(java.lang.reflect.Type t) {
  return t instanceof java.lang.reflect.ParameterizedType pt
      && pt.getActualTypeArguments().length == 1;
}

Prevention

When it happens

Trigger: A @ConfigurationProperties property type like Map<String, String> (two type arguments) or Pair<A, B> is passed to determineSingleGenericType from the value-read generators, which expect single-argument types (List, Optional, Set).

Common situations: Using Map-typed properties through the path intended for List/Optional types; custom two-parameter generic types as property types.

Related errors


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