Tencent/APIJSON · error · IllegalArgumentException

{errPrefix} 中字符 '{key}' 对应的 {column}:value 不是有效条件键值对!

Error message

{errPrefix} 中字符 '{key}' 对应的 {column}:value 不是有效条件键值对!

What it means

After resolving a @combine key, its SQL fragment wi is produced by gainWhereItem/gainHavingItem. If wi comes back empty (or blank), the key resolved to nothing usable — typically the condition value is an empty string, an empty container, or an operator with no effect — so the expression would contain an empty () group, and the request is rejected instead of emitting invalid SQL.

Source

Thrown at APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java:3518

							size++; // 兼容 key 数量判断
							wi = keyIndex > 0 ? key.substring(keyIndex + 1) : "";
							if (StringUtil.isEmpty(wi)) {
								throw new IllegalArgumentException(errPrefix + " 中字符 '"
										+ key + "' 对应的条件键值对 " + column + ":value 不存在!");
							}
						} else {
							wi = isHaving ? gainHavingItem(quote, table, alias, column, (String) value, containRaw)
									: gainWhereItem(column, value, method, verifyName);
						}

						if (1.0f*allCount/size > maxCombineRatio && maxCombineRatio > 0) {
							throw new IllegalArgumentException(errPrefix + " 中字符 '" + s + "' 不合法!"
									+ "其中 key 数量 " + allCount + " / 条件键值对数量 " + size + " = " + (1.0f*allCount/size)
									+ " 已超过 最大倍数,必须在条件键值对数量 0-" + maxCombineRatio + " 倍内!");
						}

						if (StringUtil.isEmpty(wi, true)) {  // 转成 1=1 ?
							throw new IllegalArgumentException(errPrefix + " 中字符 '" + key
									+ "' 对应的 " + column + ":value 不是有效条件键值对!");
						}

						Integer count = usedKeyCountMap.get(column);
						count = count == null ? 1 : count + 1;
						if (count > maxCombineKeyCount && maxCombineKeyCount > 0) {
							throw new IllegalArgumentException(errPrefix + " 中字符 '" + s + "' 不合法!"
									+ "其中 '" + column + "' 重复引用,次数 " + count
									+ " 已超过最大值,必须在 0-" + maxCombineKeyCount + " 内!");
						}
						usedKeyCountMap.put(column, count);

						result += "( " + gainCondition(isNot, wi) + " )";
						isNot = false;
						first = false;
					}

					key = "";

View on GitHub (pinned to 5284052872)

Solutions

  1. Omit keys with empty values from the request object entirely instead of sending "key":"".
  2. Filter empty-string/empty-collection values out of the condition map before sending (see validation code).
  3. If using placeholder keys ('col:suffix' form), ensure the suffix produces a real condition.

Example fix

// before
{"User":{"id":1,"remark":"","@combine":"id & remark"}}
// after
{"User":{"id":1,"@combine":"id"}}
Defensive patterns

Strategy: validation

Validate before calling

boolean effective = tableObj.entrySet().stream()
    .filter(e -> !e.getKey().startsWith("@"))
    .allMatch(e -> e.getValue() != null && !"".equals(String.valueOf(e.getValue()).strip())
        && !(e.getValue() instanceof Collection && ((Collection<?>) e.getValue()).isEmpty()));
if (!effective) throw new IllegalStateException("empty condition value present");

Type guard

function isEffectiveValue(v: unknown): boolean {
  if (v === null || v === undefined) return false;
  if (typeof v === 'string') return v.trim().length > 0;
  if (Array.isArray(v)) return v.length > 0;
  return true;
}

Prevention

When it happens

Trigger: @combine:"remark & id" where the request has "remark":"" (empty value) — the key exists (so 151 doesn't fire) but gainWhereItem returns an empty string. Similarly "tag{}":[] (empty array) or an @having entry whose value produces no SQL. StringUtil.isEmpty(wi, true) with trim=true is the test at line 3518.

Common situations: Optional filter fields sent as empty strings from HTML forms; dynamically added filters whose value is '' or []; JSON built with null/empty defaults that still create map entries.

Related errors


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