jwtk/jjwt · error · IllegalArgumentException

Byte array must be exactly

Error message

Byte array must be exactly ${bitsMsg(this.bitLength)}. Found ${bitsMsg(len)}

What it means

RequiredBitLengthConverter.assertLength enforces that a byte array has an exact bit length when the converter was created with exact=true. If Bytes.bitLength(bytes) differs from the configured bitLength, this IllegalArgumentException reports the required and found sizes (via Bytes.bitsMsg).

Solutions

  1. Generate or resize the byte array to the exact required length (e.g. 16 bytes for 128 bits).
  2. Use Keys.secretKeyFor(SignatureAlgorithm) or a proper key generator instead of hand-built arrays.
  3. Verify with bytes.length * 8 == requiredBits before calling the API.

Example fix

// before
byte[] key = new byte[15]; // 120 bits
// after
byte[] key = new byte[16]; // exactly 128 bits
Defensive patterns

Strategy: validation

Validate before calling

void requireExactBits(byte[] b, long bits) {
    long len = b.length * 8L; // approximate; matches Bytes.bitLength semantics
    if (len != bits) throw new IllegalArgumentException("Need exactly " + bits + " bits, got " + len);
}

Try / catch

try {
    converter.applyTo(bytes);
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Byte array must be exactly")) {
        // regenerate/resize the byte array
    }
    throw e;
}

Prevention

When it happens

Trigger: Providing a key/byte-array parameter (e.g. a 128-bit key claim) whose length in bits is not exactly the required amount, such as a 120-bit array where 128 bits is exact-required.

Common situations: Manually generated keys of the wrong size; keys trimmed or padded by other tooling; base64url-decoding inputs that lost bytes.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/91df18740f8aafb6. Report an issue: GitHub.

Appendix: source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/lang/RequiredBitLengthConverter.java:41

    private final int bitLength;
    private final boolean exact;

    public RequiredBitLengthConverter(Converter<byte[], Object> converter, int bitLength) {
        this(converter, bitLength, true);
    }

    public RequiredBitLengthConverter(Converter<byte[], Object> converter, int bitLength, boolean exact) {
        this.converter = Assert.notNull(converter, "Converter cannot be null.");
        this.bitLength = Assert.gt(bitLength, 0, "bitLength must be greater than 0");
        this.exact = exact;
    }

    private byte[] assertLength(byte[] bytes) {
        long len = Bytes.bitLength(bytes);
        if (exact && len != this.bitLength) {
            String msg = "Byte array must be exactly " + Bytes.bitsMsg(this.bitLength) + ". Found " + Bytes.bitsMsg(len);
            throw new IllegalArgumentException(msg);
        } else if (len < this.bitLength) {
            String msg = "Byte array must be at least " + Bytes.bitsMsg(this.bitLength) + ". Found " + Bytes.bitsMsg(len);
            throw new IllegalArgumentException(msg);
        }
        return bytes;
    }

    @Override
    public Object applyTo(byte[] bytes) {
        assertLength(bytes);
        return this.converter.applyTo(bytes);
    }

    @Override
    public byte[] applyFrom(Object o) {
        byte[] result = this.converter.applyFrom(o);
        return assertLength(result);
    }

View on GitHub (pinned to fb71496164)