google/gson · error · RuntimeException
Failed to invoke constructor '" + ReflectionHelper.construct
Error message
Failed to invoke constructor '" + ReflectionHelper.constructorToString(constructor) + "' with args " + Arrays.toString(accumulator)
What it means
Thrown by RecordAdapter.finalize when invoking the record's canonical constructor fails with IllegalAccessException or InstantiationException or IllegalArgumentException (wrapped into one catch). The first two should be near-impossible per Gson's own comments; IllegalArgumentException means a registered adapter returned an object of the wrong type for a constructor argument. Wrapped as a RuntimeException carrying the original exception.
Source
Thrown at gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java:656
+ " same names as the fields in the Java class, and that the order of the"
+ " RecordComponents is the same as the order of the canonical constructor"
+ " parameters.");
}
field.readIntoArray(in, componentIndex, accumulator);
}
@Override
T finalize(Object[] accumulator) {
try {
return constructor.newInstance(accumulator);
} catch (IllegalAccessException e) {
throw ReflectionHelper.createExceptionForUnexpectedIllegalAccess(e);
}
// Note: InstantiationException should be impossible because record class is not abstract;
// IllegalArgumentException should not be possible unless a bad adapter returns objects of
// the wrong type
catch (InstantiationException | IllegalArgumentException e) {
throw new RuntimeException(
"Failed to invoke constructor '"
+ ReflectionHelper.constructorToString(constructor)
+ "' with args "
+ Arrays.toString(accumulator),
e);
} catch (InvocationTargetException e) {
// TODO: JsonParseException ?
throw new RuntimeException(
"Failed to invoke constructor '"
+ ReflectionHelper.constructorToString(constructor)
+ "' with args "
+ Arrays.toString(accumulator),
e.getCause());
}
}
}
}
View on GitHub (pinned to 8b8628c656)
Solutions
- Inspect the wrapped exception: IllegalArgumentException -> fix the custom adapter for the named component type.
- Ensure the canonical constructor parameter types match what your TypeAdapters produce.
- Open the package containing the record in module-info so reflective construction is permitted.
- Register a full TypeAdapter for the record so Gson never invokes the canonical constructor reflectively.
Example fix
// before: adapter returns wrong type for primitive component
registerTypeAdapter(int.class, new TypeAdapter<Integer>(){
public Integer read(JsonReader r){ return r.nextString(); } // String for int
});
// after
public Integer read(JsonReader r){ return r.nextInt(); } Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure adapters for record components return assignable types
for (RecordComponent rc : MyRecord.class.getRecordComponents()) {
TypeAdapter<?> a = gson.getAdapter(TypeToken.get(rc.getType()));
// read a sample and check class before relying on it
} Type guard
null
Try / catch
try {
gson.fromJson(json, MyRecord.class);
} catch (RuntimeException e) {
if (e.getMessage().startsWith("Failed to invoke constructor") && !(e.getCause() instanceof InvocationTargetException)) {
// IllegalAccessException / IllegalArgumentException: fix adapter return types
} else throw e;
} Prevention
- Unit-test each custom TypeAdapter against the exact parameter type of the record constructor.
- Open the record's package to Gson in module-info to avoid IllegalAccessException.
- Keep primitive and boxed adapter registrations distinct and correct.
- Prefer InstanceCreator or full record TypeAdapters when component types are non-trivial.
When it happens
Trigger: A custom TypeAdapter registered for a record component returns a value whose type does not match the canonical constructor parameter (e.g., returns a String for an int parameter); a security manager or module layer denies constructor access after the initial makeAccessible; subclassing tools that make the record abstract. Catch site: line 655.
Common situations: Mixing custom adapters for boxed/primitive components incorrectly; JPMS layer changes after adapter construction; security managers rejecting reflection; buggy generic TypeAdapter returning wrong runtime types.
Related errors
- null is not allowed as value for record component '" + field
- duplicate key: {key}
- Expecting number, got: " + jsonToken + "; at path " + in.get
- Unexpected token: " + peeked
- Accessor " + accessorDescription + " threw exception
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/932429a22778aa2b.json.
Report an issue: GitHub.