pentaho/pentaho-kettle · error · RuntimeException

Unexpected error trying to encode object.

Error message

Unexpected error trying to encode object.

What it means

MessageEncoder.encode serializes a Message to bytes via ObjectOutputStream, then Base64+GZIP encodes it for WebSocket transmission. Any failure during serialization or encoding is wrapped in this RuntimeException because the WebSocket Encoder interface only allows RuntimeException.

Solutions

  1. Inspect the wrapped cause: NotSerializableException names the offending class — make it Serializable or mark the field transient.
  2. Review recent changes to Message classes for non-Serializable fields and fix them.
  3. Keep serialVersionUID stable when evolving Message classes to avoid InvalidClassException.
  4. Test encoding of every Message subtype in a unit test before shipping.

Example fix

// before
public class MyMessage implements Message {
  private InputStream data; // NotSerializableException
}
// after
public class MyMessage implements Message {
  private transient InputStream data;
  private byte[] dataBytes; // serializable representation
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight check that all nested values are serializable
for (Object v : messageValues) {
  if (!(v instanceof Serializable)) throw new IllegalArgumentException("Non-serializable field: " + v.getClass());
}

Try / catch

try {
  String encoded = encoder.encode(message);
} catch (RuntimeException e) {
  if (e.getCause() instanceof NotSerializableException nse) {
    logger.error("Make this Serializable or transient: " + nse.getMessage());
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling encode(Message) with an object whose field graph contains non-Serializable members; the object or a nested field's class changed without updating serialVersionUID causing serialization errors; NotSerializableException on a nested type.

Common situations: Adding a new field holding a non-Serializable type (e.g. an InputStream, Logger, or lambda) to a Message class; passing a Message subclass with transient-unsupported state; incompatible class changes after upgrade.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/fb64a0cadb6cac91. Report an issue: GitHub.

Appendix: source

Thrown at engine-ext/api/src/main/java/org/pentaho/di/engine/api/remote/MessageEncoder.java:47

 * Created by ccaspanello on 7/20/17.
 */
public class MessageEncoder implements Encoder.Text<Message> {
  /**
   * Encode the given AEL Message object into a String.
   *
   * @param object the Message object being encoded.
   * @return the encoded object as a string.
   */
  @Override
  public String encode( Message object ) throws EncodeException {
    try {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ObjectOutputStream oos = new ObjectOutputStream( baos );
      oos.writeObject( object );
      oos.close();
      return EncodeUtil.encodeBase64Zipped( baos.toByteArray() );
    } catch ( Exception e ) {
      throw new RuntimeException( "Unexpected error trying to encode object.", e );
    }
  }

  @Override
  public void init( EndpointConfig config ) {
    // Do Nothing
  }

  @Override
  public void destroy() {
    // Do Nothing
  }
}

View on GitHub (pinned to f3058517a1)