{"record":{"id":"2ba54e24c79ae0a9","repo":"dromara/Sa-Token","slug":"error-2ba54e","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":102,"sourceCode":"\t\t}\n\n\t\treturn encoded.toString();\n\t}\n\n\t@Override\n\tpublic byte[] stringToBytes(String encodedStr) {\n\t\tif (CUSTOM_CHARS.length() != 64) {\n\t\t\tthrow new IllegalStateException(\"自定义字符集长度必须为64\");\n\t\t}\n\n\t\tMap<Character, Integer> charMap = new HashMap<>();\n\t\tfor (int i = 0; i < CUSTOM_CHARS.length(); i++) {\n\t\t\tcharMap.put(CUSTOM_CHARS.charAt(i), i);\n\t\t}\n\n\t\tint length = encodedStr.length();\n\t\tif (length % 4 != 0) {\n\t\t\tthrow new IllegalArgumentException(\"编码字符串长度无效\");\n\t\t}\n\n\t\t// 计算填充符数量\n\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调整","sourceCodeStart":84,"sourceCodeEnd":120,"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#L84-L120","documentation":"Thrown by SaSerializerForBase64UseCustomCharacters.stringToBytes when the input string's length is not a multiple of 4 (IllegalArgumentException, no specific code). This custom-alphabet Base64 decoder processes 4-character groups into 3 bytes, so any string whose length % 4 != 0 cannot be a valid encoding from this serializer.","triggerScenarios":"Calling valueToString/String-to-bytes deserialization on a token or serialized string that was truncated, corrupted, or produced by a different Base64 variant/standard alphabet while the custom-characters serializer is configured.","commonSituations":"Tokens serialized with the default serializer (or standard Base64) then deserialized after switching the serializer to the custom-characters variant; strings mangled by transport (truncated by URL length limits, header stripping); whitespace/newline accidentally prepended.","solutions":["Regenerate/re-serialize the data with the same custom-characters serializer configuration so encode and decode match","Ensure the serialized string is transmitted intact: URL-encode it, avoid truncation, trim surrounding whitespace","Keep the serializer configuration identical across all services that share the data (set it globally via SaManager.setSaSerializer)"],"exampleFix":"// before (services disagree on serializer)\n// service A: SaManager.setSaSerializer(new SaSerializerForJackson())\n// service B: SaManager.setSaSerializer(new SaSerializerForBase64UseCustomCharacters(...))\n// after: configure the same serializer instance type on every service","handlingStrategy":"validation","validationCode":"String s = encodedStr == null ? \"\" : encodedStr;\nif (s.length() % 4 != 0) throw new IllegalArgumentException(\"not a valid encoding from this serializer (length % 4 != 0)\");","typeGuard":null,"tryCatchPattern":"try { byte[] data = serializer.stringToBytes(input); } catch (IllegalArgumentException e) { log.warn(\"corrupted serialized value\"); recoverFromSource(); }","preventionTips":["Pin one serializer configuration across all services that share values","Treat serialized strings as opaque: no trimming, no case changes, URL-encode in transit"],"tags":["serialization","base64","configuration","validation"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}