spring-projects/spring-security · error · IllegalArgumentException
Decoding failed
Error message
Decoding failed
What it means
Utf8.decode converts UTF-8 bytes to a String using the charset decoder, which throws CharacterCodingException when the byte array is not valid UTF-8 (malformed lead bytes, truncated multi-byte sequences, or invalid continuation bytes). The library rethrows it as IllegalArgumentException with cause "Decoding failed".
Source
Thrown at crypto/src/main/java/org/springframework/security/crypto/codec/Utf8.java:68
ByteBuffer bytes = CHARSET.newEncoder().encode(CharBuffer.wrap(string));
byte[] bytesCopy = new byte[bytes.limit()];
System.arraycopy(bytes.array(), 0, bytesCopy, 0, bytes.limit());
return bytesCopy;
}
catch (CharacterCodingException ex) {
throw new IllegalArgumentException("Encoding failed", ex);
}
}
/**
* Decode the bytes in UTF-8 form into a String.
*/
public static String decode(byte[] bytes) {
try {
return CHARSET.newDecoder().decode(ByteBuffer.wrap(bytes)).toString();
}
catch (CharacterCodingException ex) {
throw new IllegalArgumentException("Decoding failed", ex);
}
}
/**
* Constant time comparison to prevent against timing attacks.
* @param expected the expected {@link CharSequence}
* @param actual the actual {@link CharSequence}
* @return true if {@code expected} and {@code actual} are equal, false otherwise
* @since 5.7.26
*/
public static boolean isEqual(@Nullable CharSequence expected, @Nullable CharSequence actual) {
byte[] expectedBytes = bytesUtf8(expected);
byte[] actualBytes = bytesUtf8(actual);
return MessageDigest.isEqual(expectedBytes, actualBytes);
}
private static byte @Nullable [] bytesUtf8(@Nullable CharSequence s) {
return (s != null) ? Utf8.encode(s) : null;View on GitHub (pinned to 96852e8860)
Solutions
- Decode with the byte data's actual charset, or convert/repair the data to UTF-8.
- If bytes may be arbitrary binary, do not use Utf8.decode — keep them as byte[] or use Base64.
- Check truncation logic so byte arrays are not cut in the middle of a multi-byte sequence.
Example fix
// before String s = Utf8.decode(latin1Bytes); // throws // after String s = new String(latin1Bytes, StandardCharsets.ISO_8859_1); // correct source charset
Defensive patterns
Strategy: validation
Validate before calling
boolean isProbablyUtf8(byte[] b) { int i = 0; while (i < b.length) { if (b[i] >= 0) { i++; } else if ((b[i] & 0xE0) == 0xC0 && i + 1 < b.length && (b[i+1] & 0xC0) == 0x80) { i += 2; } else if ((b[i] & 0xF0) == 0xE0 && i + 2 < b.length && (b[i+1] & 0xC0) == 0x80 && (b[i+2] & 0xC0) == 0x80) { i += 3; } else return false; } return true; } Try / catch
try { s = Utf8.decode(bytes); } catch (IllegalArgumentException e) { s = new String(bytes, fallbackCharset); } Prevention
- Standardize on UTF-8 for all persisted text; set -Dfile.encoding=UTF-8 and explicit charsets everywhere.
- Record the source charset alongside byte data instead of assuming UTF-8.
- Avoid fixed-offset slicing of multi-byte encoded byte arrays.
When it happens
Trigger: Calling Utf8.decode on bytes that are not UTF-8 — e.g. Latin-1/GBK/Windows-1252 encoded text, encrypted or compressed bytes, or a byte array truncated mid multi-byte character.
Common situations: Reading files produced on a legacy system with a different default charset; decoding database blobs stored in another encoding; slicing byte arrays at fixed offsets cutting a multi-byte char.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Encoding failed
- String cannot be null
- Access is denied
- RunAsImplAuthenticationProvider.incorrectKey
- Access is denied
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/09ea9a84e2d1a20a.
Report an issue: GitHub.