Tencent/APIJSON · error · IllegalArgumentException

originKey + ":value 中字符 " + k + " 不合法!key$:value 中不允许 key 中有

Error message

originKey + ":value 中字符 " + k + " 不合法!key$:value 中不允许 key 中有连续相同的占位符!

What it means

For LIKE-type join keys ending in '$' (key$:value → key LIKE value), APIJSON lets you prepend one or two of the placeholders % _ ? (e.g. key_%$ → LIKE '_v%', key?%$ → LIKE 'v%'). While peeling the trailing placeholder chars, if two consecutive characters are the SAME placeholder (key%%$, key__$, key??$) it throws, because '%%' / '__' / '??' are redundant or ambiguous and almost certainly a typo.

Source

Thrown at APIJSONORM/src/main/java/apijson/orm/Join.java:300

				k = originKey.substring(0, originKey.length() - 2);
			}
			else if (originKey.endsWith("<>")) {
				setRelateType("<>");
				k = originKey.substring(0, originKey.length() - 2);
			}
			else if (originKey.endsWith("$")) {  // key%$:"a" -> key LIKE '%a%'; key?%$:"a" -> key LIKE 'a%'; key_?$:"a" -> key LIKE '_a'; key_%$:"a" -> key LIKE '_a%'
				k = originKey.substring(0, originKey.length() - 1);
				char c = k.isEmpty() ? 0 : k.charAt(k.length() - 1);

				String t = "$";
				if (c == '%' || c == '_' || c == '?') {
					t = c + t;
					k = k.substring(0, k.length() - 1);

					char c2 = k.isEmpty() ? 0 : k.charAt(k.length() - 1);
					if (c2 == '%' || c2 == '_' || c2 == '?') {
						if (c2 == c) {
							throw new IllegalArgumentException(originKey + ":value 中字符 " + k + " 不合法!key$:value 中不允许 key 中有连续相同的占位符!");
						}

						t = c2 + t;
						k = k.substring(0, k.length() - 1);
					}
					else if (c == '?') {
						throw new IllegalArgumentException(originKey + ":value 中字符 " + originKey + " 不合法!key$:value 中不允许只有单独的 '?',必须和 '%', '_' 之一配合使用 !");
					}
				}

				setRelateType(t);
			}
			else if (originKey.endsWith("~")) {
				boolean ignoreCase = originKey.endsWith("*~");
				setRelateType(ignoreCase ? "*~" : "~");
				k = originKey.substring(0, originKey.length() - (ignoreCase ? 2 : 1));
			}
			else if (originKey.endsWith(">=")) {

View on GitHub (pinned to 5284052872)

Solutions

  1. Use each placeholder at most once: "name_%$":"a" (LIKE '_a%'), "name?%$":"a" (LIKE 'a%').
  2. If you need consecutive placeholder characters in the actual SQL pattern, put them in the value (e.g. "name$":"%a%%") rather than the key suffix.
  3. Rename double-underscored column keys so they do not end with the placeholder+operator sequence, or alias the column.

Example fix

// before
"User":{"name%%$":"a"}  // rejected: consecutive identical placeholders
// after
"User":{"name_%$":"a"}  // LIKE '_a%'
// or put full pattern in value:
"User":{"name$":"%a%"}
Defensive patterns

Strategy: validation

Validate before calling

const LIKE_KEY = /^!?[A-Za-z]\w*(\?%|_%|\?_|\?|_|%)?\$$/;
function assertLikeJoinKey(k) {
  if (!LIKE_KEY.test(k)) throw new Error('Bad LIKE join key: ' + k);
  const m = k.match(/(.)\1\$$/);   // detects doubled trailing placeholder
  if (m) throw new Error('Consecutive identical placeholder ' + m[1] + m[1] + ' in ' + k);
}

Type guard

function isLikeJoinKey(k) { return /^!?[A-Za-z]\w*([%_?]{0,2})\$$/.test(k) && !/(.)\1\$$/.test(k); }

Prevention

When it happens

Trigger: A join table object contains a key like "name%%$":"a" (two consecutive %), "code__$":"a", or "flag??$":"a". The parser peels one '%', sees c2 == c ('%' again) and throws IllegalArgumentException listing the offending key.

Common situations: Developer intends a literal double underscore in a column name and forgets the operator parsing treats trailing _ as placeholder; typo doubling the placeholder; migrating SQL LIKE patterns ('%%' for empty pattern in some dialects) straight into key names.

Related errors


AI-assisted analysis of Tencent/APIJSON@5284052872 (2026-08-14). Data as JSON: /api/errors/6dd3e2f52faf6d16. Report an issue: GitHub.