Tencent/APIJSON · error · UnsupportedOperationException

${table}/${k} 不合法!join 关联的 Table 中,join: ?/Table/key 时只能有 1

Error message

${table}/${k} 不合法!join 关联的 Table 中,join: ?/Table/key 时只能有 1 个 key@:value;join: ?/Table 时所有 key@:value 要么是符合 join 格式,要么能直接解析成具体值!

What it means

A key@ entry in the joined table object had a path value that the parser could not resolve: getValueByPath(sv) returned null or echoed the input string back, meaning '/Table/key' does not point to an existing value in the current request. Since join: ?/Table/key permits exactly one key@ and join: ?/Table requires every key@ to be resolvable, an UnsupportedOperationException is raised (a TODO marks future JOIN ON support).

Source

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

								if (StringUtil.isName(k.substring(0, k.length() - 1)) == false) {
									throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 中 " + k + " 不合法 !" +
											"@ APP JOIN 只允许 key@:/Table/refKey 这种 = 等价连接!");
								}
							}

							refObj.put(k, v);
							continue;
						}
					}

					Object rv = getValueByPath(sv);
					if (rv != null && rv.equals(sv) == false) {
						requestObj.put(k.substring(0, k.length() - 1), rv);
						continue;
					}

					throw new UnsupportedOperationException(table + "/" + k + " 不合法!" + apijson.JSONRequest.KEY_JOIN + " 关联的 Table 中,"
							+ "join: ?/Table/key 时只能有 1 个 key@:value;join: ?/Table 时所有 key@:value 要么是符合 join 格式,要么能直接解析成具体值!");  // TODO 支持 join on
				}

				if (k.startsWith("@")) {
					if (JOIN_COPY_KEY_LIST.contains(k)) {
						requestObj.put(k, v); // 保留
					}
				}
				else {
					if (k.endsWith("@")) {
						throw new UnsupportedOperationException(table + "/" + k + " 不合法!" + apijson.JSONRequest.KEY_JOIN + " 关联的 Table 中,"
								+ "join: ?/Table/key 时只能有 1 个 key@:value;join: ?/Table 时所有 key@:value 要么是符合 join 格式,要么能直接解析成具体值!");  // TODO 支持 join on
					}

					if (k.contains("()") == false) { // 不需要远程函数
						requestObj.put(k, v); // 保留
					}
				}

View on GitHub (pinned to 5284052872)

Solutions

  1. Include the referenced table object with the referenced key in the same request: add 'User': { 'id': ... }
  2. Fix typos in the reference path so '/targetTable/targetKey' matches real keys already present
  3. Verify the target key exists in the referenced object (it must be literal-valued, not another unresolved reference)

Example fix

// before
{ 'join': '</Moment', 'Moment': { 'userId@': '/User/id' } }
// after
{ 'join': '</Moment', 'Moment': { 'userId@': '/User/id' }, 'User': { 'id': 38710 } }
Defensive patterns

Strategy: validation

Validate before calling

function resolveRefPath(req, path) {
  if (typeof path !== 'string' || !path.startsWith('/')) return null;
  let cur = req;
  for (const seg of path.split('/').filter(Boolean)) {
    if (cur == null || typeof cur !== 'object' || !(seg in cur)) return null;
    cur = cur[seg];
  }
  return cur;
}
function checkJoinRefs(req) {
  for (const [tblKey, tbl] of Object.entries(req)) {
    if (tbl && typeof tbl === 'object') {
      for (const [k, v] of Object.entries(tbl)) {
        if (k.endsWith('@') && typeof v === 'string' && v.startsWith('/') && resolveRefPath(req, v) == null) {
          return `${tblKey}/${k}: path ${v} does not resolve in this request`;
        }
      }
    }
  }
  return null;
}

Try / catch

Catch UnsupportedOperationException containing '只能有 1 个 key@:value'; re-check that every /Table/key path exists in the request payload and report the unresolved one.

Prevention

When it happens

Trigger: { 'join': '</Moment', 'Moment': { 'userId@': '/User/id' } } sent without a 'User' object in the same request; or '/User/name' where 'name' is not a key of User; or a path with a typo '/Userr/id'.

Common situations: Forgetting to include the referenced (main) table object in the same request; referencing a key the main table object does not declare; renaming tables after the join request was written.

Related errors


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