{"record":{"id":"09ea9a84e2d1a20a","repo":"spring-projects/spring-security","slug":"decoding-failed","errorCode":null,"errorMessage":"Decoding failed","messagePattern":"Decoding failed","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"crypto/src/main/java/org/springframework/security/crypto/codec/Utf8.java","lineNumber":68,"sourceCode":"\t\t\tByteBuffer bytes = CHARSET.newEncoder().encode(CharBuffer.wrap(string));\n\t\t\tbyte[] bytesCopy = new byte[bytes.limit()];\n\t\t\tSystem.arraycopy(bytes.array(), 0, bytesCopy, 0, bytes.limit());\n\t\t\treturn bytesCopy;\n\t\t}\n\t\tcatch (CharacterCodingException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Encoding failed\", ex);\n\t\t}\n\t}\n\n\t/**\n\t * Decode the bytes in UTF-8 form into a String.\n\t */\n\tpublic static String decode(byte[] bytes) {\n\t\ttry {\n\t\t\treturn CHARSET.newDecoder().decode(ByteBuffer.wrap(bytes)).toString();\n\t\t}\n\t\tcatch (CharacterCodingException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Decoding failed\", ex);\n\t\t}\n\t}\n\n\t/**\n\t * Constant time comparison to prevent against timing attacks.\n\t * @param expected the expected {@link CharSequence}\n\t * @param actual the actual {@link CharSequence}\n\t * @return true if {@code expected} and {@code actual} are equal, false otherwise\n\t * @since 5.7.26\n\t */\n\tpublic static boolean isEqual(@Nullable CharSequence expected, @Nullable CharSequence actual) {\n\t\tbyte[] expectedBytes = bytesUtf8(expected);\n\t\tbyte[] actualBytes = bytesUtf8(actual);\n\t\treturn MessageDigest.isEqual(expectedBytes, actualBytes);\n\t}\n\n\tprivate static byte @Nullable [] bytesUtf8(@Nullable CharSequence s) {\n\t\treturn (s != null) ? Utf8.encode(s) : null;","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/crypto/src/main/java/org/springframework/security/crypto/codec/Utf8.java#L50-L86","documentation":"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\".","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nString s = Utf8.decode(latin1Bytes); // throws\n// after\nString s = new String(latin1Bytes, StandardCharsets.ISO_8859_1); // correct source charset","handlingStrategy":"validation","validationCode":"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; }","typeGuard":null,"tryCatchPattern":"try { s = Utf8.decode(bytes); } catch (IllegalArgumentException e) { s = new String(bytes, fallbackCharset); }","preventionTips":["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."],"tags":["utf8","decoding-failed","spring-security","character-encoding"],"backgroundTag":"invalid-argument-format","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}