dromara/Sa-Token · error · IllegalArgumentException

非法Emoji:

Error message

非法Emoji: 

What it means

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.

Source

Thrown at sa-token-plugin/sa-token-serializer-features/src/main/java/cn/dev33/satoken/serializer/SaSerializerForBase64UseEmoji.java:88

		for (int index : indices) {
			result.append(EMOJI_TABLE.get(index));
		}
		return result.toString();
	}

	@Override
	public byte[] stringToBytes(String encoded) {
		List<Integer> indices = new ArrayList<>();

		// 提取索引(每个Emoji占2个char)
		for (int i = 0; i < encoded.length(); ) {
			if (i + 1 >= encoded.length()) break;
			String emoji = encoded.substring(i, i + 2);
			i += 2;

			Integer index = EMOJI_MAP.get(emoji);
			if (index == null) {
				throw new IllegalArgumentException("非法Emoji: " + emoji);
			}
			indices.add(index);
		}

		// 转换为二进制字符串
		StringBuilder binaryStr = new StringBuilder();
		for (int index : indices) {
			binaryStr.append(String.format("%6s", Integer.toBinaryString(index))
					.replace(' ', '0'));
		}

		// 转换为字节数组(自动处理末尾补零)
		List<Byte> bytes = new ArrayList<>();
		for (int i = 0; i < binaryStr.length(); i += 8) {
			int endIndex = Math.min(i + 8, binaryStr.length());
			String byteStr = binaryStr.substring(i, endIndex);
			if (byteStr.length() < 8) break; // 忽略末尾不足8位的部分
			bytes.add((byte) Integer.parseInt(byteStr, 2));

View on GitHub (pinned to ac2c7f6e94)

Solutions

  1. Ensure encode and decode both use SaSerializerForBase64UseEmoji on all services sharing the values
  2. Guarantee UTF-8 end to end (DB charset, Content-Type, connector parameters) so surrogate pairs survive
  3. Avoid any transformation (trim/replace/case change) of emoji-serialized strings in transit
Defensive patterns

Strategy: validation

Validate before calling

boolean ok = input.length() % 2 == 0;
for (int i = 0; ok && i < input.length(); i += 2) { ok = EMOJI_MAP.containsKey(input.substring(i, i + 2)); }
if (!ok) throw new IllegalArgumentException("string is not emoji-serializer output");

Try / catch

try { byte[] data = emojiSerializer.stringToBytes(input); } catch (IllegalArgumentException e) { log.warn("emoji decode failed — check UTF-8 integrity"); reSerialize(); }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14). Data as JSON: /api/errors/2b951be73beb9b24. Report an issue: GitHub.