Tencent/APIJSON · critical · NullPointerException

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

Error message

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

What it means

Internal NullPointerException from the JOIN-cache loop in the SQL executor: while back-filling vice-table cache configs from join ON conditions, an element of join.getOnList() is null at index j. This is a server-side data-structure invariant violation, not a user-input validation error.

Source

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

							columnIndexAndJoinMap[i - 1] = curJoin;
						}

						// 如果是主表则直接用主表对应的 item,否则缓存副表数据到 childMap
						Join prevJoin = columnIndexAndJoinMap == null || i < 2 ? null : columnIndexAndJoinMap[i - 2];
						if (curJoin != prevJoin) {  // 前后字段不在同一个表对象,即便后面出现 null,也不该是主表数据,而是逻辑 bug 导致
							SQLConfig<T, M, L> viceConfig = curJoin != null && curJoin.isSQLJoin() ? curJoin.getCacheConfig() : null;
							boolean hasPK = false;
							if (viceConfig != null) {  //FIXME 只有和主表关联才能用 item,否则应该从 childMap 查其它副表数据
								List<On> onList = curJoin.getOnList();
								int size = onList == null ? 0 : onList.size();
								if (size > 0) {
									String idKey = viceConfig.getIdKey();
									String tblKey = config.gainTableKey();
									for (int j = size - 1; j >= 0; j--) {
										On on = onList.get(j);
										String ok = on == null ? null : on.getOriginKey();
										if (ok == null) {
											throw new NullPointerException("服务器内部错误,List<Join> 中 Join.onList[" + j + (on == null ? "] = null!" : ".getOriginKey() = null!"));
										}

										String k = ok.substring(0, ok.length() - 1);
										String ttk = on.getTargetTableKey();

										M target = StringUtil.equals(ttk, tblKey) ? item : (viceItem == null ? null : JSON.get(viceItem, ttk));
										Object v = target == null ? null : target.get(on.getTargetKey());
										hasPK = hasPK || (k.equals(idKey) && v != null);

										viceConfig.putWhere(k, v, true);
									}
								}
							}

							if (viceConfig == null) { // StringUtil.isEmpty(viceSql, true)) {
								Log.i(TAG, "execute viceConfig == null >> item = null; >> ");
								curItem = null;
							}

View on GitHub (pinned to 5284052872)

Solutions

  1. Fix the joiner syntax so every ON entry parses fully: "Table/alias/key@/Target/alias2/key".
  2. If constructing Join objects in code, never add null On entries; validate before adding.
  3. Align APIJSON artifact versions (ORM vs framework) across the classpath.
  4. Report with full request body if the joiner string itself looks correct — it may be an internal bug.

Example fix

// before
join.setOnList(Arrays.asList(on, null));
// after
join.setOnList(Collections.singletonList(on));
Defensive patterns

Strategy: try-catch

Try / catch

try { result = executor.execute(config); } catch (npe) { if (npe instanceof NullPointerException && /Join\.onList\[\d+\] = null/.test(npe.message)) { log.error('join onList corrupt for {}', config.getTable(), npe); return serverError(); } throw npe; }

Prevention

When it happens

Trigger: A JOIN (typically APP JOIN on cached data) whose onList contains a null entry — usually from programmatic construction of Join/On objects or a partial deserialization of a joiner string.

Common situations: Building Join objects manually in extended code; version mismatches between APIJSON modules producing incompletely populated Join instances; malformed "Table/key@/Target/key" joiner strings that parse into sparse lists.

Related errors


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