chinabugotech/hutool · error · IllegalArgumentException

invalid number: {number}

Error message

invalid number: {number}

What it means

Hashids encodes an array of non-negative integers; the algorithm (lottery selection and per-number encoding) assumes numbers >= 0. If any element is negative the encode stream throws IllegalArgumentException naming the bad number. This is the standard Hashids contract — it cannot represent negative values.

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/codec/Hashids.java:208

	 * @param numbers 数字数组
	 * @return 编码后的值, {@code null} if {@code numbers} 是 {@code null}.
	 * @throws IllegalArgumentException 数字不支持抛出此异常
	 */
	@Override
	public String encode(final long... numbers) {
		if (numbers == null) {
			return null;
		}

		// copy alphabet
		final char[] currentAlphabet = Arrays.copyOf(alphabet, alphabet.length);

		// determine the lottery number
		final long lotteryId = LongStream.range(0, numbers.length)
				.reduce(0, (state, i) -> {
					final long number = numbers[(int) i];
					if (number < 0) {
						throw new IllegalArgumentException("invalid number: " + number);
					}
					return state + number % (i + LOTTERY_MOD);
				});
		final char lottery = currentAlphabet[(int) (lotteryId % currentAlphabet.length)];

		// encode each number
		final StringBuilder global = new StringBuilder();
		IntStream.range(0, numbers.length)
				.forEach(idx -> {
					// derive alphabet
					deriveNewAlphabet(currentAlphabet, salt, lottery);

					// encode
					final int initialLength = global.length();
					translate(numbers[idx], currentAlphabet, global, initialLength);

					// prepend the lottery
					if (idx == 0) {

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Filter or clamp values to >= 0 before encoding (e.g. Math.max(0, n)).
  2. Document that Hashids only supports non-negative integers; choose a different scheme if negatives are required.
  3. Validate the input array with Arrays.stream(...).allMatch(n -> n >= 0) before calling encode.

Example fix

// before
String h = hashids.encode(-1, 42);
// after
long[] safe = Arrays.stream(nums).map(n -> Math.max(0, n)).toArray();
String h = hashids.encode(safe);
Defensive patterns

Strategy: validation

Validate before calling

if (Arrays.stream(numbers).anyMatch(n -> n < 0)) throw new IllegalArgumentException("Hashids requires non-negative numbers");

Type guard

static boolean allNonNeg(long[] ns) { return ns != null && Arrays.stream(ns).allMatch(n -> n >= 0); }

Try / catch

try { return hashids.encode(nums); } catch (IllegalArgumentException e) { return hashids.encode(Arrays.stream(nums).map(n->Math.max(0,n)).toArray()); }

Prevention

When it happens

Trigger: hashids.encode(...numbers) where at least one number is negative; passing a List/array of Long containing negative ids.

Common situations: Encoding database ids that can be negative in test fixtures; subtracting without clamping; overflow wrapping to negative.

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/d79c93a6673331da. Report an issue: GitHub.