json-path/JsonPath · error · IllegalArgumentException
No type info in TypeRef
Error message
No type info in TypeRef
What it means
TypeRef<T> captures a generic type via a superclass reflection trick that only works when the subclass supplies actual type arguments. Instantiating the raw TypeRef (or new TypeRef() {} with no parameterization) makes getGenericSuperclass() return the plain Class TypeRef, and an IllegalArgumentException 'No type info in TypeRef' is thrown from the constructor.
Source
Thrown at json-path/src/main/java/com/jayway/jsonpath/TypeRef.java:37
/**
* Used to specify generic type information in {@link com.jayway.jsonpath.ReadContext}
*
* <code>
* TypeRef ref = new TypeRef<List<Integer>>() { };
* </code>
*
* @param <T>
*/
public abstract class TypeRef<T> implements Comparable<TypeRef<T>> {
protected final Type type;
protected TypeRef()
{
Type superClass = getClass().getGenericSuperclass();
if (superClass instanceof Class<?>) {
throw new IllegalArgumentException("No type info in TypeRef");
}
type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public Type getType() { return type; }
/**
* The only reason we define this method (and require implementation
* of <code>Comparable</code>) is to prevent constructing a
* reference without type information.
*/
@Override
public int compareTo(TypeRef<T> o) {
return 0;
}
}
View on GitHub (pinned to 62a4c9f0f6)
Solutions
- Always subclass with an explicit type argument: new TypeRef<List<String>>() {}.
- If the target type is a simple class, pass the Class directly (read(path, Class)) instead of TypeRef.
- Add a compile-time check or unit test exercising the TypeRef read so raw usage fails fast in review.
Example fix
// before
List<Map<String, Object>> list = doc.read("$.items", new TypeRef() {});
// after
List<Map<String, Object>> list = doc.read("$.items", new TypeRef<List<Map<String, Object>>>() {}); Defensive patterns
Strategy: type-guard
Validate before calling
// compile-time: declare the anonymous subclass with an explicit type argument
TypeRef<List<Map<String, Object>>> ref = new TypeRef<List<Map<String, Object>>>() {}; Type guard
static <T> TypeRef<T> typedRef(TypeRef<T> ref) { return Objects.requireNonNull(ref); } // always instantiate as new TypeRef<Concrete>() {} Try / catch
try {
return doc.read(path, typeRef);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("No type info in TypeRef")) {
throw new IllegalStateException("Pass new TypeRef<ConcreteType>() {} with a type argument", e);
}
throw e;
} Prevention
- Never instantiate raw TypeRef; always supply the generic argument.
- Prefer read(path, Class) for simple types.
- Add a unit test reading through each TypeRef used in production code.
When it happens
Trigger: new TypeRef() {} or new TypeRef() — anonymous/inline subclass without a type parameter, e.g. passing it to JsonPath.parse(...).read("$", new TypeRef(){}) instead of new TypeRef<List<Map<String,Object>>>(){}.
Common situations: Migrating from Class-based reads to TypeRef-based generic reads and forgetting the diamond/type argument; IDE auto-completing 'new TypeRef(){}' without filling in the type.
Related errors
- TypeRef not supported: " + typeName
- Criteria can not be null
- Could not parse criteria
- Criteria build exception. Complete on criteria before defini
- Options AS_PATH_LIST and ALWAYS_RETURN_LIST are not allowed
AI-assisted analysis of json-path/JsonPath@62a4c9f0f6 (2026-09-11).
Data as JSON: /api/errors/e6776e3a3f0c672d.
Report an issue: GitHub.