{"record":{"id":"2b951be73beb9b24","repo":"dromara/Sa-Token","slug":"emoji","errorCode":null,"errorMessage":"非法Emoji: ","messagePattern":"非法Emoji: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sa-token-plugin/sa-token-serializer-features/src/main/java/cn/dev33/satoken/serializer/SaSerializerForBase64UseEmoji.java","lineNumber":88,"sourceCode":"\t\tfor (int index : indices) {\n\t\t\tresult.append(EMOJI_TABLE.get(index));\n\t\t}\n\t\treturn result.toString();\n\t}\n\n\t@Override\n\tpublic byte[] stringToBytes(String encoded) {\n\t\tList<Integer> indices = new ArrayList<>();\n\n\t\t// 提取索引（每个Emoji占2个char）\n\t\tfor (int i = 0; i < encoded.length(); ) {\n\t\t\tif (i + 1 >= encoded.length()) break;\n\t\t\tString emoji = encoded.substring(i, i + 2);\n\t\t\ti += 2;\n\n\t\t\tInteger index = EMOJI_MAP.get(emoji);\n\t\t\tif (index == null) {\n\t\t\t\tthrow new IllegalArgumentException(\"非法Emoji: \" + emoji);\n\t\t\t}\n\t\t\tindices.add(index);\n\t\t}\n\n\t\t// 转换为二进制字符串\n\t\tStringBuilder binaryStr = new StringBuilder();\n\t\tfor (int index : indices) {\n\t\t\tbinaryStr.append(String.format(\"%6s\", Integer.toBinaryString(index))\n\t\t\t\t\t.replace(' ', '0'));\n\t\t}\n\n\t\t// 转换为字节数组（自动处理末尾补零）\n\t\tList<Byte> bytes = new ArrayList<>();\n\t\tfor (int i = 0; i < binaryStr.length(); i += 8) {\n\t\t\tint endIndex = Math.min(i + 8, binaryStr.length());\n\t\t\tString byteStr = binaryStr.substring(i, endIndex);\n\t\t\tif (byteStr.length() < 8) break; // 忽略末尾不足8位的部分\n\t\t\tbytes.add((byte) Integer.parseInt(byteStr, 2));","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-plugin/sa-token-serializer-features/src/main/java/cn/dev33/satoken/serializer/SaSerializerForBase64UseEmoji.java#L70-L106","documentation":"Thrown by SaSerializerForBase64UseEmoji.stringToBytes when a 2-char unit of the encoded string is not a key in the EMOJI_MAP (IllegalArgumentException '非法Emoji'). The emoji serializer encodes each 6-bit index as one emoji composed of two UTF-16 chars; an unrecognized pair means the input was not produced by this serializer or was corrupted.","triggerScenarios":"Feeding a plain, Base64, or mojibake string to the emoji decoder; UTF-8 encoding issues (e.g. a filter converting to ISO-8859-1) breaking surrogate pairs so substring(i, i+2) no longer aligns to emoji boundaries.","commonSituations":"Token serialized with a different serializer then read with the emoji one; database or HTTP layer mangling UTF-8; string manipulation (trim, case-folding) that shifts char alignment; serializer config mismatch between issuing and validating services.","solutions":["Ensure encode and decode both use SaSerializerForBase64UseEmoji on all services sharing the values","Guarantee UTF-8 end to end (DB charset, Content-Type, connector parameters) so surrogate pairs survive","Avoid any transformation (trim/replace/case change) of emoji-serialized strings in transit"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"boolean ok = input.length() % 2 == 0;\nfor (int i = 0; ok && i < input.length(); i += 2) { ok = EMOJI_MAP.containsKey(input.substring(i, i + 2)); }\nif (!ok) throw new IllegalArgumentException(\"string is not emoji-serializer output\");","typeGuard":null,"tryCatchPattern":"try { byte[] data = emojiSerializer.stringToBytes(input); } catch (IllegalArgumentException e) { log.warn(\"emoji decode failed — check UTF-8 integrity\"); reSerialize(); }","preventionTips":["Force UTF-8 on every hop: connector, DB charset, Content-Type","Never modify emoji-serialized strings in transit (no trim, no regex on them)"],"tags":["serialization","emoji","utf-8","encoding"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}