oracle/graal · error · IllegalArgumentException
Failed to serialize ${op} due to: ${cause}
Error message
Failed to serialize ${op} due to: ${cause} What it means
JsonReplayCodec's RecordedOperation serializer wraps a lower-level IllegalArgumentException that escaped while serializing the receiver, method name list, arguments, or result marker of a recorded operation. The message chains the original cause, so the real failure is in e.getMessage() and the cause chain; the operation itself (op.toString()) is included to identify which recorded call failed.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replaycomp/JsonReplayCodec.java:202
return TAG;
}
@Override
public void serialize(Object instance, JsonBuilder.ObjectBuilder objectBuilder, RecursiveSerializer serializer) throws IOException {
OperationRecorder.RecordedOperation op = (OperationRecorder.RecordedOperation) instance;
try {
serializer.serialize(op.receiver(), objectBuilder.append("recv"));
objectBuilder.append("method", Arrays.asList(op.method().methodAndParamNames()));
if (op.args() != null) {
try (JsonBuilder.ArrayBuilder arrayBuilder = objectBuilder.append("args").array()) {
for (Object arg : op.args()) {
serializer.serialize(arg, arrayBuilder.nextEntry());
}
}
}
serializer.serialize(op.resultOrMarker(), objectBuilder.append("res"));
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Failed to serialize " + op + " due to: " + e.getMessage(), e);
}
}
@SuppressWarnings("unchecked")
@Override
public OperationRecorder.RecordedOperation deserialize(EconomicMap<String, Object> json, RecursiveDeserializer deserializer, CompilationProxies.ProxyFactory proxyFactory)
throws DeserializationException {
Object recv = deserializer.deserialize(json.get("recv"), proxyFactory);
List<Object> methodProp = (List<Object>) json.get("method");
String[] methodArray = new String[methodProp.size()];
for (int i = 0; i < methodArray.length; i++) {
methodArray[i] = (String) methodProp.get(i);
}
CompilationProxy.SymbolicMethod method = new CompilationProxy.SymbolicMethod(methodArray);
List<Object> list = (List<Object>) json.get("args");
Object[] args;
if (list == null) {
args = null;View on GitHub (pinned to a66e9ccd1d)
Solutions
- Read the chained cause ('due to: ...') — it names the actual unserializable value; register an ObjectSerializer for that class in JsonReplayCodec
- Ensure recording and JSON serialization run on the same GraalVM/compiler build
- If the type is incidental, avoid recording it (narrow the recorded compiler-interface surface)
- Add a serializer analogous to the existing ones (clazz()/tag()/serialize/deserialize) and register it in the codec's serializer table
Example fix
// before: no serializer for new type X -> 'Failed to serialize op ... due to: No serializer for class X'
// after: register one
// tagSerializers.put("x", new ObjectSerializer() {
// public Class<?> clazz() { return X.class; }
// public String tag() { return "x"; }
// public void serialize(Object i, JsonBuilder.ObjectBuilder b, RecursiveSerializer s) throws IOException { ... }
// public Object deserialize(EconomicMap<String,Object> j, RecursiveDeserializer d, CompilationProxies.ProxyFactory p) { ... }
// }); Defensive patterns
Strategy: try-catch
Try / catch
try {
codec.write(compilationUnit, writer);
} catch (IllegalArgumentException e) {
Throwable root = getRootCause(e); // walk e.getCause() chain
// root names the actual unserializable value; report it, do not retry blindly
throw new ReplaySerializationException("op failed: " + e.getMessage(), root);
} Prevention
- Run recording and JSON serialization in the same JVM/build so serializer coverage matches recorded types
- When adding compiler-interface methods, add serializers for new parameter types in the same change
- Log the recorded operation type when serialization fails to speed up serializer gaps diagnosis
When it happens
Trigger: Serializing a RecordedOperation whose receiver or argument object has no registered ObjectSerializer (propagates as IllegalArgumentException from RecursiveSerializer), or whose method()/args()/resultOrMarker() returns something the codec cannot encode.
Common situations: Recording a compilation that touches a compiler-interface type for which no serializer was registered (new JDK/Graal version adds a type); a recorded value being of an exotic class; serializing proxies created by a mismatched codec version.
Related errors
- Invalid replay string table index
- Invalid replay string definition index
- Invalid replay symbolic method index
- Invalid replay symbolic method definition index
- Invalid replay registration index
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/f7a529280d1c6c8a.
Report an issue: GitHub.