frohoff/ysoserial · error · MarshalException
unable to read objID
Error message
unable to read objID
What it means
In JRMPListener.doCall, the listener reads the ObjID from the ObjectInputStream; if reading throws an IOException it rethrows as java.rmi.MarshalException("unable to read objID", e). This means the JRMP call stream was truncated or malformed at the very first field of the call message.
Solutions
- Verify the connecting client actually speaks Java RMI/JRMP
- Inspect the wrapped cause (e.getCause()) to distinguish EOF from corrupt data
- Ensure the client sends the complete call message (ObjID + method + hash)
- Retry if the network may have truncated the stream
Defensive patterns
Strategy: try-catch
Validate before calling
// confirm the peer speaks JRMP before treating it as a call stream // e.g. verify the transport op byte matches TransportConstants.Call
Try / catch
try {
listenerSession();
} catch (MarshalException e) {
if (e.getMessage().equals("unable to read objID")) {
// log cause; likely non-JRMP client or truncated stream
}
} Prevention
- Keep scanners/probes off the JRMP listener port
- Ensure clients send the complete call message (ObjID, method, hash)
- Inspect the MarshalException cause for EOF vs corruption
When it happens
Trigger: The incoming stream does not contain a well-formed ObjID at the point doCall expects it — stream ends early, bytes are corrupt, or the sender is not speaking the JRMP call protocol at all.
Common situations: Non-JRMP clients (probes, HTTP requests) hitting the listener port; a truncated packet due to network issues; a client with an incompatible protocol version sending a different framing.
Understand the failure class
Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.
Related errors
- unknown transport op
- Not allowed to read object
- Failed to get object id
- Failed to get object id, separator
- mismatched columns
AI-assisted analysis of frohoff/ysoserial@218bcffcaa (2026-09-12).
Data as JSON: /api/errors/7cb1dee3df2af1a7.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/ysoserial/exploit/JRMPListener.java:265
@Override
protected Class<?> resolveClass ( ObjectStreamClass desc ) throws IOException, ClassNotFoundException {
if ( "[Ljava.rmi.server.ObjID;".equals(desc.getName())) {
return ObjID[].class;
} else if ("java.rmi.server.ObjID".equals(desc.getName())) {
return ObjID.class;
} else if ( "java.rmi.server.UID".equals(desc.getName())) {
return UID.class;
}
throw new IOException("Not allowed to read object");
}
};
ObjID read;
try {
read = ObjID.read(ois);
}
catch ( java.io.IOException e ) {
throw new MarshalException("unable to read objID", e);
}
if ( read.hashCode() == 2 ) {
ois.readInt(); // method
ois.readLong(); // hash
System.err.println("Is DGC call for " + Arrays.toString((ObjID[])ois.readObject()));
}
System.err.println("Sending return with payload for obj " + read);
out.writeByte(TransportConstants.Return);// transport op
ObjectOutputStream oos = new JRMPClient.MarshalOutputStream(out, this.classpathUrl);
oos.writeByte(TransportConstants.ExceptionalReturn);
new UID().write(oos);
BadAttributeValueExpException ex = new BadAttributeValueExpException(null);View on GitHub (pinned to 218bcffcaa)