jwtk/jjwt · error · IllegalArgumentException

numBytes argument must be >= 0

Error message

numBytes argument must be >= 0

What it means

Bytes.random(numBytes) generates a secure random byte array of the requested size and rejects numBytes <= 0 with an IllegalArgumentException. Note the message says >= 0 while the check is numBytes <= 0, so effectively only strictly positive sizes are allowed. It is normally reached indirectly via Bytes.randomBits(numBits).

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/lang/Bytes.java:45

    private static final int INT_BYTE_LENGTH = Integer.SIZE / Byte.SIZE;
    public static final String LONG_REQD_MSG = "Long byte arrays must be " + LONG_BYTE_LENGTH + " bytes in length.";
    public static final String INT_REQD_MSG = "Integer byte arrays must be " + INT_BYTE_LENGTH + " bytes in length.";

    //prevent instantiation
    private Bytes() {
    }

    public static byte[] nullSafe(byte[] bytes) {
        return bytes != null ? bytes : Bytes.EMPTY;
    }

    public static byte[] randomBits(int numBits) {
        return random(numBits / Byte.SIZE);
    }

    public static byte[] random(int numBytes) {
        if (numBytes <= 0) {
            throw new IllegalArgumentException("numBytes argument must be >= 0");
        }
        byte[] bytes = new byte[numBytes];
        Randoms.secureRandom().nextBytes(bytes);
        return bytes;
    }

    public static byte[] toBytes(int i) {
        return new byte[]{
                (byte) (i >>> 24),
                (byte) (i >>> 16),
                (byte) (i >>> 8),
                (byte) i
        };
    }

    public static byte[] toBytes(long l) {
        return new byte[]{
                (byte) (l >>> 56),

View on GitHub (pinned to fb71496164)

Solutions

  1. Pass at least 1 byte: Bytes.random(16) for a 128-bit value, etc.
  2. For randomBits, request at least 8 bits (or round up: (numBits + 7) / 8).
  3. Validate configured sizes (from properties/env) are > 0 before calling.

Example fix

// before
byte[] iv = Bytes.randomBits(config.getIvBits()); // 0 bits -> crash
// after
int bits = Math.max(config.getIvBits(), 128);
byte[] iv = Bytes.random((bits + 7) / Byte.SIZE);
Defensive patterns

Strategy: validation

Validate before calling

if (numBytes <= 0) {
    throw new IllegalArgumentException("need at least 1 random byte, got " + numBytes);
}
byte[] bytes = Bytes.random(numBytes);

Try / catch

try {
    byte[] bytes = Bytes.random(n);
} catch (IllegalArgumentException e) {
    bytes = Bytes.random(16); // sensible default
}

Prevention

When it happens

Trigger: Calling Bytes.random(0) or Bytes.random(negativeInt), or Bytes.randomBits with numBits in [0, 7] since numBits / 8 truncates to 0.

Common situations: Generating an IV/nonce/salt with a size computed from configuration that resolved to 0; requesting fewer than 8 random bits via randomBits; integer division silently truncating a bit-length below one byte.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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