alibaba/COLA · error · IllegalArgumentException

size must be greater than zero.

Error message

size must be greater than zero.

What it means

Argument-validation guard inside NanoIdUtils.randomNanoId: the requested id length (size parameter) was zero or negative, so the generator loop could never produce any characters. It fires when a caller passes a non-positive size to the full overload; the default path uses size 21 and cannot trigger it.

Source

Thrown at cola-components/cola-component-job/src/main/java/com/alibaba/cola/job/UuidGenerator.java:69

        public static final SecureRandom DEFAULT_NUMBER_GENERATOR = new SecureRandom();
        public static final char[] DEFAULT_ALPHABET = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
        public static final int DEFAULT_SIZE = 21;

        private NanoIdUtils() {
        }

        public static String randomNanoId() {
            return randomNanoId(DEFAULT_NUMBER_GENERATOR, DEFAULT_ALPHABET, 21);
        }

        public static String randomNanoId(Random random, char[] alphabet, int size) {
            if (random == null) {
                throw new IllegalArgumentException("random cannot be null.");
            } else if (alphabet == null) {
                throw new IllegalArgumentException("alphabet cannot be null.");
            } else if (alphabet.length != 0 && alphabet.length < 256) {
                if (size <= 0) {
                    throw new IllegalArgumentException("size must be greater than zero.");
                } else {
                    int mask = (2 << (int)Math.floor(Math.log((double)(alphabet.length - 1)) / Math.log(2.0D))) - 1;
                    int step = (int)Math.ceil(1.6D * (double)mask * (double)size / (double)alphabet.length);
                    StringBuilder idBuilder = new StringBuilder();

                    while(true) {
                        byte[] bytes = new byte[step];
                        random.nextBytes(bytes);

                        for(int i = 0; i < step; ++i) {
                            int alphabetIndex = bytes[i] & mask;
                            if (alphabetIndex < alphabet.length) {
                                idBuilder.append(alphabet[alphabetIndex]);
                                if (idBuilder.length() == size) {
                                    return idBuilder.toString();
                                }
                            }
                        }

View on GitHub (pinned to 352e1a8675)

Solutions

  1. Pass size > 0 (the library default is 21)
  2. Clamp or default invalid configured lengths before calling: size = size > 0 ? size : 21
  3. Fix the computation that produced a non-positive size

Example fix

// before
int size = config.getSize(); // could be 0
String id = randomNanoId(random, alphabet, size);
// after
int size = Math.max(1, config.getSize() > 0 ? config.getSize() : 21);
String id = randomNanoId(random, alphabet, size);
Defensive patterns

Strategy: validation

Validate before calling

if (size <= 0) {
    throw new IllegalArgumentException("size must be positive, got " + size);
}

Type guard

int sanitizedSize(int requested) {
    return requested > 0 ? requested : 21;
}

Try / catch

try {
    id = UuidGenerator.randomNanoId(random, alphabet, size);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("size")) {
        id = UuidGenerator.randomNanoId(random, alphabet, 21);
    } else throw e;
}

Prevention

When it happens

Trigger: Calling randomNanoId(random, alphabet, 0) or a negative size, often size coming from a computed or configured value.

Common situations: A config value of 0 treated as 'use default' by the caller but not by the library; int arithmetic yielding 0 or negative; passing length of an empty string.

Related errors


AI-assisted analysis of alibaba/COLA@352e1a8675 (2026-09-08). Data as JSON: /api/errors/5e4b62469ee8d79b. Report an issue: GitHub.