{"record":{"id":"f905d8cf4ec6fbda","repo":"pentaho/pentaho-kettle","slug":"unexpected-error-trying-to-decode-object-messagedecoder","errorCode":null,"errorMessage":"Unexpected error trying to decode object.","messagePattern":"Unexpected error trying to decode object\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"engine-ext/api/src/main/java/org/pentaho/di/engine/api/remote/MessageDecoder.java","lineNumber":49,"sourceCode":" */\npublic class MessageDecoder implements Decoder.Text<Message> {\n  /**\n   * Decode the given String into an AEL Message object.\n   *\n   * @param string string to be decoded.\n   * @return the decoded message as an Message object.\n   */\n  @Override\n  public Message decode( String string ) throws DecodeException {\n    try {\n      byte[] data = EncodeUtil.decodeBase64Zipped( string );\n      InputStream is = new ByteArrayInputStream( data );\n      ObjectInputStream ois = new ObjectInputStream( is );\n      Object o = ois.readObject();\n      ois.close();\n      return (Message) o;\n    } catch ( Exception e ) {\n      throw new RuntimeException( \"Unexpected error trying to decode object.\", e );\n    }\n  }\n\n  @Override\n  public boolean willDecode( String s ) {\n    return true;\n  }\n\n  @Override\n  public void init( EndpointConfig config ) {\n    // Do Nothing\n  }\n\n  @Override\n  public void destroy() {\n    // Do Nothing\n  }\n","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine-ext/api/src/main/java/org/pentaho/di/engine/api/remote/MessageDecoder.java#L31-L67","documentation":"MessageDecoder.decode deserializes a byte array back into a Message via Java ObjectInputStream during WebSocket decoding. Any failure — invalid serialized stream, class not found on the classpath, wrong cast — is wrapped in this RuntimeException.","triggerScenarios":"A WebSocket text/binary message whose decoded bytes are not a Java-serialized Message; the serialized class is missing from the receiving side's classpath (ClassNotFoundException); the deserialized object is not a Message (ClassCastException).","commonSituations":"Producer and consumer running different Pentaho/Kettle versions with incompatible serialized classes; sending non-Java-serialized data (e.g. plain JSON) to an endpoint expecting serialized Message objects; missing engine-ext jar on the decoder side.","solutions":["Ensure both sides use the same versions of the classes being serialized (Message and its payload types).","Confirm the sender uses MessageEncoder/EncodeUtil.encodeBase64Zipped, not a different serialization format.","Check the wrapped cause: ClassNotFoundException means add the missing jar; StreamCorruptedException means wrong bytes; ClassCastException means wrong object type.","Verify serialVersionUids match if custom classes were changed between versions."],"exampleFix":"// before\nObject o = ois.readObject(); // ClassNotFoundException wrapped at runtime\n// after\ntry (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data))) {\n  Object o = ois.readObject();\n  if (!(o instanceof Message)) {\n    throw new IllegalArgumentException(\"Unexpected payload type: \" + o.getClass());\n  }\n  return (Message) o;\n} catch (ClassNotFoundException e) {\n  throw new IllegalStateException(\"Message class missing on decoder classpath: \" + e.getMessage(), e);\n}","handlingStrategy":"try-catch","validationCode":"if (data == null || data.length == 0) throw new IllegalArgumentException(\"no bytes to decode\");","typeGuard":"// after decode, narrow before use\nif (obj instanceof Message) { Message m = (Message) obj; }","tryCatchPattern":"try {\n  Message m = decoder.decode(data);\n} catch (RuntimeException e) {\n  Throwable cause = e.getCause();\n  if (cause instanceof ClassNotFoundException) {\n    logger.error(\"Missing class on decoder side: \" + cause.getMessage());\n  }\n  throw e;\n}","preventionTips":["Keep identical versions of Message classes and their dependencies on producer and consumer.","Pin serialVersionUID on all serializable Message classes.","Never send non-Java-serialized payloads to an endpoint using MessageDecoder."],"tags":["serialization","websocket","deserialization","classpath"],"backgroundTag":"json-decode-failed","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}