apache/kafka · error · IllegalArgumentException

Input string with prefix `str.substring(0, 24)` is too long

Error message

Input string with prefix `str.substring(0, 24)` is too long to be decoded as a base64 UUID

What it means

Thrown by Uuid.fromString when the input string is longer than 24 characters — base64-url encoding of a 128-bit UUID is at most 22 chars plus optional padding, so anything over 24 cannot decode to 16 bytes. Uuid.fromString is the inverse of Uuid.toString(), which uses Base64.getUrlEncoder().withoutPadding(); passing a standard hyphenated java.util.UUID string (36 chars) or any non-Kafka UUID format triggers this. It is a guard against misusing the Kafka-internal base64 Uuid format (used for topic IDs and similar) with external UUID formats.

Source

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

    public int hashCode() {
        long xor = mostSignificantBits ^ leastSignificantBits;
        return (int) (xor >> 32) ^ (int) xor;
    }

    /**
     * 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);

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Use the value produced by Uuid.toString() (base64-url, no padding, <=22 chars) as the input to Uuid.fromString — these two methods are a matched pair.
  2. If you have a java.util.UUID, convert via new UUID(mostSigBits, leastSigBits) then construct org.apache.kafka.common.Uuid from its longs, or base64-encode its 16 bytes yourself.
  3. Double-check you are passing a topic ID (base64) and not a topic name into Admin APIs that take Uuid.
  4. Trim and validate the string length (<=22 ideally) before calling fromString; reject canonical-format UUIDs upstream.

Example fix

// before
Uuid k = Uuid.fromString("550e8400-e29b-41d4-a716-446655440000");  // 36 chars -> throws 299

// after
java.util.UUID ju = java.util.UUID.fromString("550e8400-e29b-41d4-a716-446655440000");
Uuid k = new Uuid(ju.getMostSignificantBits(), ju.getLeastSignificantBits());
// or, round-trip a Kafka Uuid: Uuid.fromString(k.toString())
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate length and base64-alphabet before calling Uuid.fromString:
import java.util.Base64;
import java.util.regex.Pattern;

private static final Pattern B64URL_NO_PAD = Pattern.compile("^[A-Za-z0-9_-]{0,24}$");

public static boolean isParsableUuid(String s) {
    if (s == null || s.length() > 24 || !B64URL_NO_PAD.matcher(s).matches()) return false;
    try {
        byte[] decoded = Base64.getUrlDecoder().decode(s);
        return decoded.length == 16;
    } catch (IllegalArgumentException ex) {
        return false;
    }
}

// Usage:
if (!isParsableUuid(candidate)) {
    throw new IllegalArgumentException("Not a base64-encoded Kafka Uuid: " + candidate);
}
Uuid id = Uuid.fromString(candidate);

Type guard

import java.util.Base64;
import java.util.regex.Pattern;

private static final Pattern KAFKA_UUID = Pattern.compile("^[A-Za-z0-9_-]{1,24}$");

public static boolean isKafkaUuidString(Object o) {
    if (!(o instanceof String)) return false;
    String s = (String) o;
    if (!KAFKA_UUID.matcher(s).matches()) return false;
    try {
        return Base64.getUrlDecoder().decode(s).length == 16;
    } catch (IllegalArgumentException ex) {
        return false;
    }
}

// TypeScript variant (if consuming via TS bridge):
// export const isKafkaUuid = (s: unknown): s is string =>
//   typeof s === "string" && /^[A-Za-z0-9_-]{1,24}$/.test(s) &&
//   Buffer.from(s, "base64url").length === 16;

Try / catch

try {
    Uuid id = Uuid.fromString(input);
} catch (IllegalArgumentException e) {
    // Distinguish kafka topic-id Uuids from java.util.UUID strings at the boundary:
    throw new IllegalArgumentException("Expected a Kafka base64url Uuid (<=24 chars, 16 bytes), got: "
        + (input == null ? "null" : "'" + input.substring(0, Math.min(input.length(), 24)) + "'"), e);
}

Prevention

When it happens

Trigger: Calling Uuid.fromString with: a java.util.UUID.toString() value like "123e4567-e89b-12d3-a456-426614174000" (36 chars); a canonical hex UUID; a topic name mistaken for a topic ID; any base64 string longer than 24 chars; a string with embedded newlines/whitespace inflating its length.

Common situations: Treating Kafka's org.apache.kafka.common.Uuid like java.util.UUID and feeding it standard-format UUIDs; passing a topic *name* into an API that wants a topic *id* (KIP-516 topic IDs); copying UUID strings between systems that use different encodings; trimming/parsing bugs that leave extra characters; loading IDs from JSON/DB where they were stored in canonical form.

Related errors


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