Tencent/APIJSON · error · IllegalArgumentException

{errPrefix} 中字符 '{s}' 不合法!其中 '{column}' 重复引用,次数 {count} 已超过最

Error message

{errPrefix} 中字符 '{s}' 不合法!其中 '{column}' 重复引用,次数 {count} 已超过最大值,必须在 0-{maxCombineKeyCount} 内!

What it means

usedKeyCountMap tracks how many times each column is referenced while parsing @combine. After incrementing, if count exceeds maxCombineKeyCount (>0), the request is rejected. This is a per-key cap — stricter and earlier than the aggregate ratio check (error 152) — preventing a single column from being repeated dozens of times in one expression.

Source

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

							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 = "";
					lastLogic = 0;

					if (isOver) {
						break;
					}
				}

View on GitHub (pinned to 5284052872)

Solutions

  1. Reference each key at most maxCombineKeyCount times; hoist common terms: "a & (b | c | d)" instead of repeating a.
  2. Raise maxCombineKeyCount server-side if repetition is legitimate.
  3. Lint generated combine strings for duplicate-key counts before sending (see validation code).

Example fix

// before
{"@combine":"(a & b) | (a & c) | (a & d)"}
// after
{"@combine":"a & (b | c | d)"}
Defensive patterns

Strategy: validation

Validate before calling

Map<String, Long> counts = Arrays.stream(combine.replaceAll("[()!]", " ").split("\\s*[&|]\\s*"))
    .collect(Collectors.groupingBy(k -> k.split(":")[0], Collectors.counting()));
if (counts.values().stream().anyMatch(c -> MAX_COMBINE_KEY_COUNT > 0 && c > MAX_COMBINE_KEY_COUNT))
    throw new IllegalStateException("key referenced too often");

Type guard

function keyCountsWithin(combine: string, max: number): boolean {
  const m = new Map<string, number>();
  for (const t of combine.replace(/[()!]/g, ' ').split(/\s*[&|]\s*/)) {
    const k = t.split(':')[0]; m.set(k, (m.get(k) ?? 0) + 1);
    if (m.get(k)! > max) return false;
  }
  return true;
}

Prevention

When it happens

Trigger: @combine:"a & a & a & a & a" with maxCombineKeyCount set (e.g. 5 by default in hardened deployments): the 6th reference to 'a' throws at line 3525. Distinct keys are unaffected; only repetition of one column counts.

Common situations: Generated expressions that fan one flag into many branches ("(a & b) | (a & c) | (a & d) ..."); security tuning that lowered maxCombineKeyCount; upgrading to an APIJSON version where per-key caps became configurable/enabled.

Related errors


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