Tencent/APIJSON · error · IllegalArgumentException

@join:value 中 value 值 {} 不合法!必须为 &/Table0,</Table1/key1,@/Ta

Error message

@join:value 中 value 值 {} 不合法!必须为 &/Table0,</Table1/key1,@/Table1:alias2/key2,... 或 { '&/Table0':{}, '</Table1/key1':{},... } 这种形式!

What it means

Each @join entry path must contain '/' separating join type from Table(/key): '&/User/id'. If indexOf("/") < 0 the path has no slash and IllegalArgumentException is thrown listing the required forms. This fires after the value-shape check, when the key itself is malformed.

Source

Thrown at APIJSONORM/src/main/java/apijson/orm/AbstractParser.java:1616

			Log.e(TAG, "onJoinParse  set == null || set.isEmpty() >> return null;");
			return null;
		}

		List<Join<T, M, L>> joinList = new ArrayList<>();

		for (Entry<String, Object> e : set) {  // { &/User:{}, </Moment/id@":{}, @/Comment/toId@:{} }
			// 分割 /Table/key
			String path = e == null ? null : e.getKey();
			Object outer = path == null ? null : e.getValue();

			if (outer instanceof Map<?, ?> == false) {
				throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":value 中value不合法!"
						+ "必须为 &/Table0/key0,</Table1/key1,... 或 { '&/Table0/key0':{}, '</Table1/key1':{},... } 这种形式!");
			}

			int index = path == null ? -1 : path.indexOf("/");
			if (index < 0) {
				throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":value 中 value 值 " + path + " 不合法!"
						+ "必须为 &/Table0,</Table1/key1,@/Table1:alias2/key2,... 或 { '&/Table0':{}, '</Table1/key1':{},... } 这种形式!");
			}
			String joinType = path.substring(0, index); //& | ! < > ( ) <> () *
			//			if (StringUtil.isEmpty(joinType, true)) {
			//				joinType = "|"; // FULL JOIN
			//			}
			path = path.substring(index + 1);

			index = path.lastIndexOf("/");
			String tableKey = index < 0 ? path : path.substring(0, index); // User:owner
			int index2 = tableKey.lastIndexOf("/");
			String arrKey = index2 < 0 ? null : tableKey.substring(0, index2);
			if (arrKey != null && isArrayKey(arrKey) == false) {
				throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 对应的 " + arrKey + " 不是合法的数组 key[] !" +
						"@ APP JOIN 最多允许跨 1 层,只能是子数组,且数组对象中不能有 join: value 键值对!");
			}

			tableKey = index2 < 0 ? tableKey : tableKey.substring(index2+1);

View on GitHub (pinned to 5284052872)

Solutions

  1. Always include the slash: '&/User', '@/Comment/toId' etc.
  2. Pick a valid join type prefix (& | ! < > ( ) <> () * @) before the slash
  3. Prefer the map form to make each path visually explicit and testable
  4. Add a client-side regex check like ^[&|!<>()*@]?/\w+(/\w+)?$ per entry

Example fix

// before
{"@join":"&User"}
// after
{"@join":"&/User/id"}
Defensive patterns

Strategy: validation

Validate before calling

for (String p : joinPaths) {
  if (!p.matches("^[&|!<>()*@]{0,2}/\\w+(:\\w+)?(/\\w+@?)?$")) throw new IllegalArgumentException("bad join path: " + p);
}

Type guard

boolean joinPathHasSlash(String path) { return path != null && path.indexOf('/') > 0; }

Prevention

When it happens

Trigger: "@join":"&User" or map key "&User" (missing slash), or an empty-string join type without slash like "User". Also a lone '/' edge or leading whitespace corrupting indexOf.

Common situations: Omitting the join-type sigil; using '@' APP JOIN as '@User' without slash; hand-built strings; trimming or encoding steps that strip the slash.

Related errors


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