apple/pkl · error · IllegalStateException
JavaType token must be parameterized.
Error message
JavaType token must be parameterized.
What it means
JavaType<T> is a super-type-token: the protected no-arg constructor captures T via the concrete subclass's generic superclass. It throws IllegalStateException when the class using it is not a parameterized subclass (raw JavaType or non-generic subclass), because then there is no TypeArgument to capture into the type field.
Source
Thrown at pkl-config-java/src/main/java/org/pkl/config/java/JavaType.java:100
*/
public class JavaType<T> {
private final Type type;
/**
* Constructs a {@code JavaType} using the super-type token idiom.
*
* <p>Subclasses must be parameterized with the desired type, for example:
*
* <pre>{@code
* new JavaType<List<@Nullable String>>() {}
* }</pre>
*
* @throws IllegalStateException if this instance is not parameterized
*/
protected JavaType() {
var superclass = getClass().getGenericSuperclass();
if (!(superclass instanceof ParameterizedType parameterizedType)) {
throw new IllegalStateException("JavaType token must be parameterized.");
}
type = parameterizedType.getActualTypeArguments()[0];
}
private JavaType(Type type) {
this.type = type;
}
/** Creates a {@code JavaType} for the given type. */
public static <T> JavaType<T> of(Class<T> type) {
return new JavaType<>(type);
}
/**
* Creates a {@code JavaType} for the given {@link Type}.
*
* <p>Use this method when the target type is already available as a {@link Type}; otherwise,
* prefer {@link #of(Class)}.View on GitHub (pinned to f3efcbfc9b)
Solutions
- Instantiate as a parameterized anonymous subclass: new JavaType<List<String>>() {}.
- If you already have a java.lang.reflect.Type, use the private/alternative constructor path or mapper APIs that accept a Type directly instead of the token.
- Never write raw new JavaType(); always supply the generic argument.
Example fix
// before
JavaType type = new JavaType<>() {}; // raw target, no reified argument
// after
JavaType<Map<String, String>> type = new JavaType<Map<String, String>>() {}; Defensive patterns
Strategy: type-guard
Validate before calling
// ensure the token class carries a reified type argument
static <T> JavaType<T> token(Class<? extends JavaType<T>> impl) {
return java.lang.reflect.Modifier.isAbstract(impl.getModifiers())
? fail("JavaType subclass must be concrete and parameterized")
: instantiate(impl);
} Type guard
static boolean isParameterized(JavaType<?> t) {
return t.getClass().getGenericSuperclass() instanceof ParameterizedType pt
&& pt.getActualTypeArguments()[0] instanceof Class<?>;
} Try / catch
try {
JavaType<List<String>> t = new JavaType<List<String>>() {};
return mapper.map(value, t);
} catch (IllegalStateException e) {
throw new IllegalArgumentException("Use new JavaType<T>() {} with an explicit type", e);
} Prevention
- Always instantiate JavaType as a parameterized anonymous subclass: new JavaType<Map<K,V>>() {}
- Never use the raw type new JavaType() or new JavaType<>() assigned to a raw variable
- For dynamically-known types, prefer mapper APIs that accept java.lang.reflect.Type
- Store shared tokens as static final constants so the pattern is copied correctly
When it happens
Trigger: Instantiating JavaType anonymously or as a subclass without a type argument, e.g. new JavaType() {...} instead of new JavaType<Map<String, String>>() {}, or referencing JavaType.class directly as a raw type.
Common situations: Copy-pasting a JavaType snippet but dropping the diamond type argument; using JavaType with a type variable erased at runtime; building a generic helper that instantiates new JavaType<T>() where T is not reified by a subclass.
Related errors
- Error invoking constructor of class `%s`.
- Error accessing constructor of class `%s`.
- Error invoking constructor `%s`.
- wrongTypeArgumentCount
- Did not find expected Java class `%s` on the classpath for P
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/4482c3ed83db016f.
Report an issue: GitHub.