apache/pulsar · error · IllegalArgumentException
Invalid messageId value
Error message
Invalid messageId value
What it means
ReaderHandler.getMessageId successfully Base64-decodes the 'messageId' parameter, but MessageIdImpl.fromByteArray cannot parse the decoded bytes into a valid MessageId (wrong length, malformed ledger/entry layout), so it rethrows as 'Invalid messageId value'. The bytes were encoded correctly but are not a Pulsar MessageId serialized form.
Source
Thrown at pulsar-websocket/src/main/java/org/apache/pulsar/websocket/ReaderHandler.java:405
private MessageId getMessageId() {
MessageId messageId = MessageId.latest;
String messageIdParam = queryParams.get("messageId");
if (isNotBlank(messageIdParam)) {
if (messageIdParam.equals("earliest")) {
messageId = MessageId.earliest;
} else if (!messageIdParam.equals("latest")) {
final byte[] decoded;
try {
decoded = Base64.getDecoder().decode(messageIdParam);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid messageId base64 value", e);
}
try {
messageId = MessageIdImpl.fromByteArray(decoded);
} catch (IOException | RuntimeException e) {
throw new IllegalArgumentException("Invalid messageId value", e);
}
}
}
return messageId;
}
}
View on GitHub (pinned to 820761864e)
Solutions
- Serialize the id with MessageId.toByteArray() on the producer side and base64-encode those exact bytes before passing them as ?messageId
- Use the SDK's built-in base64 message-id helpers instead of hand-rolling the encoding
- Confirm the id comes from the same Pulsar cluster/version (serialization format compatibility)
- Fall back to 'earliest' or 'latest' when a concrete id is unavailable
Example fix
// before String param = Base64.getEncoder().encodeToString(msgId.toString().getBytes()); // after String param = Base64.getEncoder().encodeToString(msgId.toByteArray());
Defensive patterns
Strategy: validation
Validate before calling
byte[] raw = Base64.getDecoder().decode(messageIdParam); if (raw.length < 12) { throw new IllegalArgumentException("decoded messageId too short to be a Pulsar MessageId"); } Type guard
boolean isPlausibleMessageId(byte[] decoded) { return decoded != null && decoded.length >= new MessageIdImpl(0,0,0).toByteArray().length; } Try / catch
try { byte[] decoded = Base64.getDecoder().decode(param); return MessageIdImpl.fromByteArray(decoded); } catch (IOException | RuntimeException e) { return MessageId.latest; } Prevention
- Only encode MessageId.toByteArray() output — never the id's toString()
- Round-trip test: decode(base64(encode(id))).equals(id)
- Use SDK helpers for message-id <-> base64 conversion
- Keep producer and consumer on compatible Pulsar client versions
When it happens
Trigger: ?messageId=<base64> decodes cleanly but the bytes are not a serialized MessageId — e.g. random data, a Pulsar broker messageId from a different serialization format, or a base64 of a string like 'ledger:entry'.
Common situations: Base64-encoding a textual message-id representation instead of the raw byte array from MessageId.toByteArray(); mixing message id formats across Pulsar versions; decoding an ack-set-augmented id whose byte layout was hand-trimmed incorrectly.
Related errors
- This method is not supported
- Size of data received by BooleanSchema is not 1
- Size of data received by ByteSchema is not 1
- Size of data received by DoubleSchema is not 8
- Missing required permitMessages field for 'permit' command
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/af178806760afcf9.
Report an issue: GitHub.