dromara/Sa-Token · error · IllegalArgumentException
无效字符:
Error message
无效字符:
What it means
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.
Source
Thrown at sa-token-plugin/sa-token-serializer-features/src/main/java/cn/dev33/satoken/serializer/SaSerializerForBase64UseCustomCharacters.java:124
int paddingCount = 0;
for (int i = length - 1; i >= 0 && encodedStr.charAt(i) == PAD_CHAR; i--) {
paddingCount++;
}
int numGroups = length / 4;
byte[] decoded = new byte[numGroups * 3 - paddingCount];
int decodedIndex = 0;
for (int group = 0; group < numGroups; group++) {
int[] indices = new int[4];
for (int j = 0; j < 4; j++) {
char c = encodedStr.charAt(group * 4 + j);
if (c == PAD_CHAR) {
indices[j] = 0; // 填充符处理为0,后续根据paddingCount调整
} else {
Integer index = charMap.get(c);
if (index == null) {
throw new IllegalArgumentException("无效字符: " + c);
}
indices[j] = index;
}
}
int combined = (indices[0] << 18) | (indices[1] << 12) | (indices[2] << 6) | indices[3];
for (int k = 0; k < 3; k++) {
if (decodedIndex < decoded.length) {
decoded[decodedIndex++] = (byte) ((combined >> (16 - 8 * k)) & 0xFF);
}
}
}
return decoded;
}
}
View on GitHub (pinned to ac2c7f6e94)
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
Defensive patterns
Strategy: validation
Validate before calling
java.util.Set<Character> alphabet = new java.util.HashSet<>();
for (char c : CUSTOM_CHARS.toCharArray()) alphabet.add(c);
boolean ok = input.chars().allMatch(c -> alphabet.contains((char) c) || c == PAD_CHAR);
if (!ok) throw new IllegalArgumentException("string contains chars outside the custom alphabet"); Try / catch
try { byte[] data = serializer.stringToBytes(input); } catch (IllegalArgumentException e) { log.warn("alphabet mismatch on decode"); reSerializeFromSource(); } Prevention
- Freeze CUSTOM_CHARS after first release; changing it invalidates stored data
- Share the alphabet constant via one library module used by every service
When it happens
Trigger: Deserializing a standard Base64 string (containing '+', '/', '=') while the custom alphabet excludes those characters, or mixing two different custom alphabets between the writer and reader.
Common situations: 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.
Related errors
- 编码字符串长度无效
- 12002
- UsernameAndPassword 不能为空
- 未配置全局 Http Digest 认证参数
- 全局 Http Digest 认证参数配置错误,格式应如:username:password
AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14).
Data as JSON: /api/errors/f7a1435e66cce1b0.
Report an issue: GitHub.