chinabugotech/hutool · error · IllegalArgumentException

Invalid char ' ' at [ ]

Error message

Invalid char '{}' at [{}]

What it means

Base58Codec's decoder maps each input char through a lookup table; chars not in the Base58 alphabet (excludes 0, O, I, l and all non-alphanumeric) or any char >= 128 yield digit -1 and an IllegalArgumentException naming the char and index. This is the decode-side input validation, distinct from the checksum check (error 37).

Solutions

  1. Trim and strip all whitespace before decoding.
  2. Validate the input matches the Base58 alphabet regex ^[1-9A-HJ-NP-Za-km-z]+$ before calling decode.
  3. Reject inputs containing the forbidden look-alike chars (0,O,I,l).

Example fix

// before
byte[] d = Base58.decode(" 1BvBMSE  YstWetqTFn5\n");
// after
String clean = userInput.trim().replaceAll("\\s", "");
if (!clean.matches("^[1-9A-HJ-NP-Za-km-z]+$")) throw new IllegalArgumentException("bad base58");
byte[] d = Base58.decode(clean);
Defensive patterns

Strategy: validation

Validate before calling

String clean = input.trim().replaceAll("\\s", "");
if (!clean.matches("^[1-9A-HJ-NP-Za-km-z]+$")) throw new IllegalArgumentException("invalid base58 char in: " + input);

Type guard

static boolean isBase58(String s) { return s != null && s.matches("^[1-9A-HJ-NP-Za-km-z]+$"); }

Try / catch

try { return Base58.decode(s); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("bad base58", e); }

Prevention

When it happens

Trigger: Decoding a string with whitespace, 0/O/I/l, punctuation, or non-ASCII chars via Base58Codec.decode / Base58.decode. A copy-paste that included spaces or newlines.

Common situations: User-supplied Base58 with formatting whitespace; mistaking Base64/Base32 output for Base58; locale-specific characters in the input.

Related errors


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

Appendix: source

Thrown at hutool-core/src/main/java/cn/hutool/core/codec/Base58Codec.java:137

			final int length = alphabet.length();
			for (int i = 0; i < length; i++) {
				lookupTable[alphabet.charAt(i)] = (byte) i;
			}
			this.lookupTable = lookupTable;
		}

		@Override
		public byte[] decode(CharSequence encoded) {
			if (encoded.length() == 0) {
				return new byte[0];
			}
			// Convert the base58-encoded ASCII chars to a base58 byte sequence (base58 digits).
			final byte[] input58 = new byte[encoded.length()];
			for (int i = 0; i < encoded.length(); ++i) {
				char c = encoded.charAt(i);
				int digit = c < 128 ? lookupTable[c] : -1;
				if (digit < 0) {
					throw new IllegalArgumentException(StrUtil.format("Invalid char '{}' at [{}]", c, i));
				}
				input58[i] = (byte) digit;
			}
			// Count leading zeros.
			int zeros = 0;
			while (zeros < input58.length && input58[zeros] == 0) {
				++zeros;
			}
			// Convert base-58 digits to base-256 digits.
			byte[] decoded = new byte[encoded.length()];
			int outputStart = decoded.length;
			for (int inputStart = zeros; inputStart < input58.length; ) {
				decoded[--outputStart] = divmod(input58, inputStart, 58, 256);
				if (input58[inputStart] == 0) {
					++inputStart; // optimization - skip leading zeros
				}
			}
			// Ignore extra leading zeroes that were added during the calculation.

View on GitHub (pinned to 8870454b2a)