apple/pkl · error · IllegalArgumentException

Target type `%s` is missing type arguments.

Error message

Target type `%s` is missing type arguments.

What it means

ValueMapperImpl.getConverter looks up/builds a Converter for (sourceType, targetType). If targetType is a parameterized type whose arguments were erased/unspecified (Reflection.isMissingTypeArguments), the mapper cannot know what to convert to and refuses with this error rather than guessing.

Source

Thrown at pkl-config-java/src/main/java/org/pkl/config/java/mapper/ValueMapperImpl.java:82

      return rawTargetType;
    }
    var rawRegisteredSchema = Reflection.toRawType(determinedClass);
    if (rawTargetType.isAssignableFrom(rawRegisteredSchema)) {
      return rawRegisteredSchema;
    }
    return rawTargetType;
  }

  @Override
  public <S, T> Converter<S, T> getConverter(PClassInfo<S> sourceType, Type targetType) {
    Tuple2<PClassInfo<?>, Type> key = Tuple2.of(sourceType, targetType);

    @SuppressWarnings("unchecked")
    Converter<S, T> converter = (Converter<S, T>) convertersMap.get(key);
    if (converter != null) return converter;

    if (Reflection.isMissingTypeArguments(targetType)) {
      throw new IllegalArgumentException(
          String.format("Target type `%s` is missing type arguments.", targetType));
    }

    Class<?> rawTargetType = getTargetType(sourceType, targetType);
    @SuppressWarnings("unchecked")
    var rawImplType = (Class<T>) typeMappingsMap.getOrDefault(rawTargetType, rawTargetType);
    var implType = Reflection.getExactSubtype(targetType, rawImplType);

    // look up implType converter
    // because implType has wildcards removed, conversion to
    // `? extends Number` or `? super Number` finds converter for `Number`
    // (assuming `converters` has such a converter)
    var implKey = Tuple2.of(sourceType, implType);
    @SuppressWarnings("unchecked")
    var implConverter = (Converter<S, T>) convertersMap.get(implKey);
    if (implConverter != null) {
      // TODO: give converter a chance to copy itself to avoid pollution of its inline caches
      convertersMap.put(key, implConverter);

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Pass a fully parameterized target type, e.g. Types.parameterizedType(List.class, String.class).
  2. Use the Types helpers (listOf, setOf, mapOf-equivalent) to construct the target type.
  3. Avoid erased Types from reflection; use getGenericType() instead of getReturnType()/getClass().

Example fix

// before
mapper.map(pklObject, List.class);
// after
mapper.map(pklObject, Types.parameterizedType(List.class, String.class));
Defensive patterns

Strategy: type-guard

Validate before calling

if (targetType instanceof Class<?> c && c.getTypeParameters().length > 0) throw new IllegalArgumentException("parameterize " + c);

Type guard

static boolean hasTypeArguments(Type t) { return t instanceof ParameterizedType || (t instanceof Class<?> c && c.getTypeParameters().length == 0); }

Try / catch

try { mapper.map(src, targetType); } catch (IllegalArgumentException e) { /* rebuild targetType with Types.parameterizedType */ }

Prevention

When it happens

Trigger: Calling valueMapper.map(source, targetType) with a raw generic Class such as List.class or Map.class as the target, or a Type whose actual type arguments are absent.

Common situations: Passing List.class instead of a ParameterizedType built via Types.parameterizedType/List.of-style typing; obtaining the target Type via reflection from an erased field or method return.

Related errors


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/a7eb252db84d962e. Report an issue: GitHub.