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

  1. Take the class name from the message and register an ObjectSerializer (clazz/tag/serialize/deserialize) for it in JsonReplayCodec
  2. If it is a JDK type, serialize it structurally (e.g. by name string) rather than by proxy
  3. Re-record and serialize with the same GraalVM build so the type sets match
  4. 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

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


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/a2452c17303fa31b. Report an issue: GitHub.