apache/pulsar · error · IllegalArgumentException

Invalid messageId base64 value

Error message

Invalid messageId base64 value

What it means

ReaderHandler.getMessageId decodes the 'messageId' query parameter from Base64 before reconstructing a MessageIdImpl. When the parameter is not valid Base64, java.util.Base64 throws IllegalArgumentException and the handler rethrows it with the 'Invalid messageId base64 value' message. This happens before the more specific 'Invalid messageId value' check that validates the decoded bytes.

Source

Thrown at pulsar-websocket/src/main/java/org/apache/pulsar/websocket/ReaderHandler.java:399

        int size = DEFAULT_RECEIVER_QUEUE_SIZE;
        if (queryParams.containsKey("receiverQueueSize")) {
            size =  Math.min(Integer.parseInt(queryParams.get("receiverQueueSize")), DEFAULT_RECEIVER_QUEUE_SIZE);
        }
        return size;
    }

    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

  1. URL-encode the messageId parameter (Base64 '+' and '/' become %2B and %2F)
  2. Verify the messageId string is complete and copied from the corresponding base64 encoding of the raw message id
  3. Use the literal 'earliest' or 'latest' when you want boundary positions instead of a concrete id
  4. Fix the message id at the source: read it from the received message's message-id field, not hand-crafted strings

Example fix

// before
GET /websocket/reader/t/p?messageId=CgAAAA==
// after
GET /websocket/reader/t/p?messageId=CgAAAA%3D%3D
Defensive patterns

Strategy: validation

Validate before calling

String safe = URLEncoder.encode(messageIdParam, StandardCharsets.UTF_8); if (messageIdParam.isEmpty() || !(messageIdParam.equals("earliest") || messageIdParam.equals("latest") || safe.equals(messageIdParam))) { throw new IllegalArgumentException("messageId must be earliest, latest, or URL-encoded base64"); }

Type guard

boolean isUrlSafeBase64(String s) { return s.matches("[A-Za-z0-9+/=\-%.]*") && !s.isEmpty(); }

Try / catch

try { openReader(topic, messageIdParam); } catch (IllegalArgumentException e) { log.warn("bad messageId param: {}", messageIdParam); openReader(topic, "latest"); }

Prevention

When it happens

Trigger: GET /websocket/reader/<topic> with ?messageId=<value> where value contains characters outside the Base64 alphabet (spaces, '+', unencoded '/' or '='), e.g. a URL-unencoded or truncated message id.

Common situations: Not URL-encoding a raw message id that contains '+/=' characters; copying a message id from logs and truncating it; sending an empty or non-id string such as 'latest' misspelled.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/1a9d6157539f1b75. Report an issue: GitHub.