apache/kafka · error · IllegalArgumentException

Input string `str` decoded as uuidBytes.remaining() bytes, w

Error message

Input string `str` decoded as uuidBytes.remaining() bytes, which is not equal to the expected 16 bytes of a base64-encoded UUID

What it means

Thrown by Uuid.fromString(String) when the supplied string, after URL-safe Base64 decoding, does not yield exactly 16 bytes (a 128-bit UUID). Kafka's Uuid.toString() produces a 22-character unpadded URL-safe Base64 string (Base64.getUrlEncoder().withoutPadding()), and fromString() is its strict inverse, so any other encoding (dashed hex, padded Base64, truncated data, raw text) is rejected. The IllegalArgumentException surfaces a corrupt or wrongly-formatted topic/partition ID string that the caller expected to round-trip into a Uuid.

Source

Thrown at clients/src/main/java/org/apache/kafka/common/Uuid.java:142

     * Returns a base64 string encoding of the UUID.
     */
    @Override
    public String toString() {
        return Base64.getUrlEncoder().withoutPadding().encodeToString(getBytesFromUuid());
    }

    /**
     * Creates a UUID based on a base64 string encoding used in the toString() method.
     */
    public static Uuid fromString(String str) {
        if (str.length() > 24) {
            throw new IllegalArgumentException("Input string with prefix `"
                + str.substring(0, 24) + "` is too long to be decoded as a base64 UUID");
        }

        ByteBuffer uuidBytes = ByteBuffer.wrap(Base64.getUrlDecoder().decode(str));
        if (uuidBytes.remaining() != 16) {
            throw new IllegalArgumentException("Input string `" + str + "` decoded as "
                + uuidBytes.remaining() + " bytes, which is not equal to the expected 16 bytes "
                + "of a base64-encoded UUID");
        }

        return new Uuid(uuidBytes.getLong(), uuidBytes.getLong());
    }

    private byte[] getBytesFromUuid() {
        // Extract bytes for uuid which is 128 bits (or 16 bytes) long.
        ByteBuffer uuidBytes = ByteBuffer.wrap(new byte[16]);
        uuidBytes.putLong(this.mostSignificantBits);
        uuidBytes.putLong(this.leastSignificantBits);
        return uuidBytes.array();
    }

    @Override
    public int compareTo(Uuid other) {
        if (mostSignificantBits > other.mostSignificantBits) {

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Only pass values that were produced by Uuid.toString() (22-char unpadded URL-safe Base64) into Uuid.fromString().
  2. If you hold a java.util.UUID, convert with new Uuid(jUuid.getMostSignificantBits(), jUuid.getLeastSignificantBits()) instead of string parsing.
  3. If you have a hex/dashed UUID string, parse it with java.util.UUID.fromString() first, then build the Kafka Uuid from its two longs.
  4. Validate length and charset (URL-safe Base64 alphabet, 22 chars, no padding) before calling fromString() to give a clearer upstream error.

Example fix

// before
Uuid id = Uuid.fromString(javaUuid.toString()); // dashed hex, decodes to != 16 bytes

// after
java.util.UUID j = java.util.UUID.fromString(javaUuid.toString());
Uuid id = new Uuid(j.getMostSignificantBits(), j.getLeastSignificantBits());
Defensive patterns

Strategy: validation

Validate before calling

// Validate a candidate string is a round-trippable Kafka Uuid before calling Uuid.fromString(...)
String s = /* untrusted */;
if (s == null || s.length() > 24) { /* reject: wrong shape */ }
byte[] decoded;
try {
    decoded = Base64.getUrlDecoder().decode(s);
} catch (IllegalArgumentException e) { /* reject: not valid url-safe base64 */ }
if (decoded.length != 16) { /* reject: not a UUID payload */ }
// Only now: Uuid.fromString(s);

Type guard

// Narrow an arbitrary Object/String to a base64-encoded Kafka Uuid
static boolean isBase64UuidString(Object o) {
    if (!(o instanceof String)) return false;
    String s = (String) o;
    if (s.length() > 24) return false;
    byte[] d;
    try { d = Base64.getUrlDecoder().decode(s); }
    catch (IllegalArgumentException e) { return false; }
    return d.length == 16;
}

Try / catch

// Only when input truly cannot be pre-validated
try {
    Uuid id = Uuid.fromString(s);
} catch (IllegalArgumentException e) {
    // covers both the length-prefixed message and the 16-byte message;
    // treat as malformed identifier, do not retry with the same input
}

Prevention

When it happens

Trigger: Calling Uuid.fromString(str) where str is a java.util.UUID-style dashed hex string (36 chars), a standard (non-URL-safe or padded) Base64 string, a value shorter/longer than 22 chars that doesn't decode to 16 bytes, or an arbitrary string token. Happens when deserializing a topic-id stored in a config file, JSON payload, URL path parameter, or command-line arg and passing it directly into Uuid.fromString().

Common situations: Persisting a Uuid via toString() but later reconstructing it from a different representation (e.g. storing the java.util.UUID.toString() form); copy/paste truncating a 22-char base64 id; migrating from older code that used UUID.fromString(); reading topic IDs from KRaft metadata tooling output or AdminClient responses and feeding them back in the wrong format.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/cbb763ef76068b58.json. Report an issue: GitHub.