oracle/graal · error · NotSerializableException

UnsupportedTypeException serialization is not supported.

Error message

UnsupportedTypeException serialization is not supported.

What it means

UnsupportedTypeException (thrown by Truffle interop when guest values do not match a parameter/accessor type) deliberately blocks Java serialization. Its private writeObject always throws NotSerializableException because the exception carries polyglot value references that cannot be faithfully serialized. Attempting to write such an exception through ObjectOutputStream triggers this failure.

Source

Thrown at espresso/src/com.oracle.truffle.espresso.polyglot/src/com/oracle/truffle/espresso/polyglot/UnsupportedTypeException.java:118

     * supported.
     * <p>
     * In addition a cause may be provided. The cause should only be set if the guest language code
     * caused this problem. An example for this is a language specific proxy mechanism that invokes
     * guest language code to describe an object. If the guest language code fails to execute and
     * this interop exception is a valid interpretation of the error, then the error should be
     * provided as cause.
     *
     * @param cause the guest language exception that caused the error.
     * 
     * @since 21.0
     */
    public static UnsupportedTypeException create(Object[] suppliedValues, String hint, Throwable cause) {
        return new UnsupportedTypeException(hint, suppliedValues, cause);
    }

    @SuppressWarnings({"static-method", "unused"})
    private void writeObject(ObjectOutputStream outputStream) throws IOException {
        throw new NotSerializableException(UnsupportedTypeException.class.getSimpleName() + " serialization is not supported.");
    }
}

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Do not serialize the exception itself; extract and serialize the message string and class name instead.
  2. Before serializing a Throwable chain, walk getCause()/getSuppressed() and replace any UnsupportedTypeException with a plain RuntimeException carrying its message.
  3. If using a framework with pluggable serializers, switch that message type to a string-based serializer.
  4. Log the full exception locally (toString includes the offending values) and ship only the log record.

Example fix

// before
objectOutputStream.writeObject(caughtException); // may contain UnsupportedTypeException

// after
Throwable safe = caughtException;
if (safe instanceof UnsupportedTypeException ute) {
    safe = new RuntimeException(ute.getClass().getName() + ": " + ute.getMessage());
}
objectOutputStream.writeObject(safe);
Defensive patterns

Strategy: try-catch

Try / catch

try {
    out.writeObject(throwable);
} catch (NotSerializableException e) {
    out.writeObject(sanitize(throwable)); // replace UnsupportedTypeException in the chain with a plain RuntimeException
}

Prevention

When it happens

Trigger: Calling ObjectOutputStream.writeObject on an UnsupportedTypeException (or on a Throwable graph containing one, e.g. serializing a request-scoped exception to a remote node or into a session). Also triggered by frameworks that auto-serialize exceptions (RMI, Spring session, akka serialization, distributed test runners).

Common situations: Polyglot/Espresso apps that propagate interop type errors across process boundaries; saving exceptions to disk for later inspection; sending exceptions over a message queue. Works locally, fails only when the exception crosses a serialization boundary.

Related errors


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