{"record":{"id":"f7a1435e66cce1b0","repo":"dromara/Sa-Token","slug":"error-f7a143","errorCode":null,"errorMessage":"无效字符: ","messagePattern":"无效字符: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sa-token-plugin/sa-token-serializer-features/src/main/java/cn/dev33/satoken/serializer/SaSerializerForBase64UseCustomCharacters.java","lineNumber":124,"sourceCode":"\t\tint paddingCount = 0;\n\t\tfor (int i = length - 1; i >= 0 && encodedStr.charAt(i) == PAD_CHAR; i--) {\n\t\t\tpaddingCount++;\n\t\t}\n\n\t\tint numGroups = length / 4;\n\t\tbyte[] decoded = new byte[numGroups * 3 - paddingCount];\n\t\tint decodedIndex = 0;\n\n\t\tfor (int group = 0; group < numGroups; group++) {\n\t\t\tint[] indices = new int[4];\n\t\t\tfor (int j = 0; j < 4; j++) {\n\t\t\t\tchar c = encodedStr.charAt(group * 4 + j);\n\t\t\t\tif (c == PAD_CHAR) {\n\t\t\t\t\tindices[j] = 0; // 填充符处理为0，后续根据paddingCount调整\n\t\t\t\t} else {\n\t\t\t\t\tInteger index = charMap.get(c);\n\t\t\t\t\tif (index == null) {\n\t\t\t\t\t\tthrow new IllegalArgumentException(\"无效字符: \" + c);\n\t\t\t\t\t}\n\t\t\t\t\tindices[j] = index;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tint combined = (indices[0] << 18) | (indices[1] << 12) | (indices[2] << 6) | indices[3];\n\t\t\tfor (int k = 0; k < 3; k++) {\n\t\t\t\tif (decodedIndex < decoded.length) {\n\t\t\t\t\tdecoded[decodedIndex++] = (byte) ((combined >> (16 - 8 * k)) & 0xFF);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn decoded;\n\t}\n}\n","sourceCodeStart":106,"sourceCodeEnd":141,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-plugin/sa-token-serializer-features/src/main/java/cn/dev33/satoken/serializer/SaSerializerForBase64UseCustomCharacters.java#L106-L141","documentation":"Thrown by SaSerializerForBase64UseCustomCharacters.stringToBytes when a character in the encoded string (other than the pad char) is not present in the configured 64-character custom alphabet (IllegalArgumentException '无效字符: c'). The decoder maps each character to its index in CUSTOM_CHARS; an unknown character means the string was not produced by this alphabet.","triggerScenarios":"Deserializing a standard Base64 string (containing '+', '/', '=') while the custom alphabet excludes those characters, or mixing two different custom alphabets between the writer and reader.","commonSituations":"Swapping CUSTOM_CHARS order between versions/services so previously valid encodings now decode differently or fail; standard Base64 tokens fed to the custom serializer; copy-paste introduces a look-alike Unicode character.","solutions":["Make the writer and reader use the exact same CUSTOM_CHARS string (same order), ideally defined in one shared constant","If the data is standard Base64, use the standard serializer instead of the custom-characters one","Treat CUSTOM_CHARS as immutable after first release; changing it invalidates all previously serialized values"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"java.util.Set<Character> alphabet = new java.util.HashSet<>();\nfor (char c : CUSTOM_CHARS.toCharArray()) alphabet.add(c);\nboolean ok = input.chars().allMatch(c -> alphabet.contains((char) c) || c == PAD_CHAR);\nif (!ok) throw new IllegalArgumentException(\"string contains chars outside the custom alphabet\");","typeGuard":null,"tryCatchPattern":"try { byte[] data = serializer.stringToBytes(input); } catch (IllegalArgumentException e) { log.warn(\"alphabet mismatch on decode\"); reSerializeFromSource(); }","preventionTips":["Freeze CUSTOM_CHARS after first release; changing it invalidates stored data","Share the alphabet constant via one library module used by every service"],"tags":["serialization","base64","alphabet","configuration"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}