oracle/graal · error · IllegalArgumentException
No serializer for ${instanceClass}: ${instance}
Error message
No serializer for ${instanceClass}: ${instance} What it means
RecursiveSerializer.serialize(Object, ValueBuilder) dispatches by looking up an ObjectSerializer: first an exact-class map, then a scan of interface-keyed serializers (with result caching into the exact-class map). If neither finds a handler, it throws IllegalArgumentException naming the class and instance — the recorded object graph contains a type the codec was never taught to serialize.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replaycomp/JsonReplayCodec.java:1900
private final RecursiveSerializer recursiveSerializer = new RecursiveSerializer() {
@Override
public void serialize(Object instance, JsonBuilder.ValueBuilder valueBuilder) throws IOException {
if (instance == null) {
valueBuilder.value(null);
return;
}
ObjectSerializer serializer = exactClassSerializers.get(instance.getClass());
if (serializer == null) {
var cursor = interfaceSerializers.getEntries();
while (cursor.advance()) {
if (cursor.getKey().isInstance(instance)) {
serializer = cursor.getValue();
exactClassSerializers.put(instance.getClass(), serializer);
break;
}
}
if (serializer == null) {
throw new IllegalArgumentException("No serializer for " + instance.getClass() + ": " + instance);
}
}
try (JsonBuilder.ObjectBuilder builder = valueBuilder.object()) {
builder.append("tag", serializer.tag());
serializer.serialize(instance, builder, this);
}
}
@Override
public void serialize(Object instance, JsonBuilder.ValueBuilder valueBuilder, String tag) throws IOException {
if (instance == null) {
valueBuilder.value(null);
return;
}
ObjectSerializer serializer = tagSerializers.get(tag);
if (serializer == null) {
throw new IllegalArgumentException("No serializer registered for the given tag " + tag);
}View on GitHub (pinned to a66e9ccd1d)
Solutions
- Take the class name from the message and register an ObjectSerializer (clazz/tag/serialize/deserialize) for it in JsonReplayCodec
- If it is a JDK type, serialize it structurally (e.g. by name string) rather than by proxy
- Re-record and serialize with the same GraalVM build so the type sets match
- Filter the offending value out of recording if it is not needed for replay
Defensive patterns
Strategy: try-catch
Try / catch
try {
serializer.serialize(value, valueBuilder);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("No serializer for")) {
// log class name, skip or structurally encode the value; do not corrupt the stream silently
LOG.warning("Unhandled replay type: " + e.getMessage());
} else { throw e; }
} Prevention
- Keep serializer coverage in lockstep with the recorded compiler interface: one change adds the type and its serializer
- Add a canSerialize(Object) probe API in forks to assert coverage before a long recording run
- Run a smoke serialize right after recording so gaps fail fast, not at replay time
When it happens
Trigger: Any recorded value whose class implements none of the registered serializer classes/interfaces — typically a new JDK/Graal type introduced by version drift, or an object reaching the recorder through a custom compiler-interface method.
Common situations: Upgrading one side (recorder or serializer) of a replay workflow without the other; custom compiler-interface extensions recording domain objects; unexpected java.* types (Class, MethodHandles, lambdas) leaking into recorded results.
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/a2452c17303fa31b.
Report an issue: GitHub.