Tencent/APIJSON · critical · NullPointerException

服务器内部错误,List<Join> 中 Join.onList[0] = null!

Error message

服务器内部错误,List<Join> 中 Join.onList[0] = null!

What it means

Internal NullPointerException from executeAppJoin: for an @ APP JOIN the executor requires exactly one ON condition, but onList is null/empty (or its first element is null), so on == null and originKey cannot be read. APP JOIN cannot fetch and cache vice-table rows without the ON relation.

Source

Thrown at APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java:782

					Log.i(TAG, "executeAppJoin  for (Join j : joinList) >> j.isAppJoin() == false >>  continue;");
					continue;
				}

				SQLConfig<T, M, L> cc = join.getCacheConfig(); //这里用config改了getSQL后再还原很麻烦,所以提前给一个config2更好
				if (cc == null) {
					if (Log.DEBUG) {
						throw new NullPointerException("服务器内部错误, executeAppJoin cc == null ! 导致不能缓存 @ APP JOIN 的副表数据!");
					}
					continue;
				}

				SQLConfig<T, M, L> jc = join.getJoinConfig();

				List<On> onList = join.getOnList();
				On on = onList == null || onList.isEmpty() ? null : onList.get(0);  // APP JOIN 应该有且只有一个 ON 条件
				String originKey = on == null ? null : on.getOriginKey();
				if (originKey == null) {
					throw new NullPointerException("服务器内部错误,List<Join> 中 Join.onList[0" + (on == null ? "] = null!" : ".getOriginKey() = null!"));
				}
				String key = on.getKey();
				if (key == null) {
					throw new NullPointerException("服务器内部错误,List<Join> 中 Join.onList[0" + (on == null ? "] = null!" : ".getKey() = null!"));
				}

				// 取出 "id@": "@/User/userId" 中所有 userId 的值
				List<Object> targetValueList = new ArrayList<>();

				for (int i = 0; i < resultList.size(); i++) {
					M mainTable = resultList.get(i);
					Object targetValue = mainTable == null ? null : mainTable.get(on.getTargetKey());

					if (targetValue != null && targetValueList.contains(targetValue) == false) {
						targetValueList.add(targetValue);
					}
				}

View on GitHub (pinned to 5284052872)

Solutions

  1. Give the APP JOIN a complete relation: "Comment/userId@/User/id": "@ APP" style joiner with the /key@/Table/key mapping.
  2. When building Join programmatically, always attach a non-empty onList with a valid first On.
  3. If the joiner string is correct, check for version mismatch and report upstream.

Example fix

// before
"join": {"Comment@": "@ APP"}
// after
"join": {"Comment/userId@/User/id": "@ APP"}
Defensive patterns

Strategy: validation

Validate before calling

// validate APP JOIN entry has a full relation before sending
const JOINER = /^[\w$]+\/[^/@]+@\/?[\w$]+\/[^/@]+$/;
for (const jk of Object.keys(body['@join'] || {})) {
  if (!JOINER.test(jk)) throw new Error('malformed join key: ' + jk);
}

Try / catch

try { executor.execute(config); } catch (npe) { if (npe instanceof NullPointerException && /Join\.onList\[0\] = null/.test(String(npe.getMessage()))) { log.error('APP JOIN missing ON condition'); throw new BadRequestException('join needs /key@/Table/key'); } throw npe; }

Prevention

When it happens

Trigger: A "@ APP" type join entry whose onList was never populated — e.g. joiner string missing the key@ mapping segment, or a Join built in code without On conditions.

Common situations: Malformed join key like "Comment@ User" (no /userId@/User/id part); partial deserialization of join config; custom Join construction for APP JOIN without ON.

Related errors


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