Tencent/APIJSON · error · UnsupportedOperationException

@having:value 的 value 中字符串 ${expression} 不合法!不允许传超过 100 个字符的

Error message

@having:value 的 value 中字符串 ${expression} 不合法!不允许传超过 100 个字符的函数或表达式!请用 @raw 简化传参!

What it means

gainHavingItem rejects any @having expression longer than 100 characters. Long expressions are treated as a smell (attempted injection or oversized payload); the library explicitly tells you to move such SQL into @raw so it is served from the server-side RAW_MAP whitelist instead of client input.

Source

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

		//fun0(arg0,arg1,...);fun1(arg0,arg1,...)
		String havingString = parseCombineExpression(getMethod(), getQuote(), getTable()
				, getAlias(), map, getHavingCombine(), true, containRaw, true);

		return (hasPrefix ? " HAVING " : "") + StringUtil.concat(havingString, joinHaving, AND);
	}

	protected String gainHavingItem(String quote, String table, String alias
			, String key, String expression, boolean containRaw) throws Exception {
		//fun(arg0,arg1,...)
		if (containRaw) {
			String rawSQL = gainRawSQL(KEY_HAVING, expression);
			if (rawSQL != null) {
				return rawSQL;
			}
		}

		if (expression.length() > 100) {
			throw new UnsupportedOperationException("@having:value 的 value 中字符串 " + expression + " 不合法!"
					+ "不允许传超过 100 个字符的函数或表达式!请用 @raw 简化传参!");
		}

		int start = expression.indexOf("(");
		if (start < 0) {
			if (isPrepared() && PATTERN_FUNCTION.matcher(expression).matches() == false) {
				throw new UnsupportedOperationException("字符串 " + expression + " 不合法!"
						+ "预编译模式下 @having:\"column?value;function(arg0,arg1,...)?value...\""
						+ " 中 column?value 必须符合正则表达式 " + PATTERN_FUNCTION + " 且不包含连续减号 -- !不允许空格!");
			}
			
			return parseSQLExpression(KEY_HAVING, expression, containRaw, false, null);
		}

		int end = expression.lastIndexOf(")");
		if (start >= end) {
			throw new IllegalArgumentException("字符 " + expression + " 不合法!"
					+ "@having:value 中 value 里的 SQL函数必须为 function(arg0,arg1,...) 这种格式!");

View on GitHub (pinned to 5284052872)

Solutions

  1. Split logic: keep the numeric comparison in @having and move complex function text into a RAW_MAP entry referenced by @raw
  2. Shorten by using aliases defined in @column (e.g. alias 'sum' then "@having": "sum>10")
  3. Backend: add the full expression to RAW_MAP (key -> SQL) and pass the key via @raw

Example fix

// before
{"@column": "sum(amount):s", "@having": "sum(amount)>1000 and max(created_at)>'2024-01-01' and min(level)>=2 and count(*)>5"}
// after
{"@column": "sum(amount):s", "@raw": "@having", "@having": "amountFilter"}  // amountFilter -> full SQL configured in backend RAW_MAP
Defensive patterns

Strategy: validation

Validate before calling

const hv = obj['@having'];
if (typeof hv === 'string' && hv.length > 100) {
  throw new Error('@having expression >100 chars; move it to a backend RAW_MAP entry and use @raw');
}

Type guard

const havingWithinLimit = s => typeof s === 'string' && s.length <= 100;

Try / catch

try { await api.get(req); } catch (e) { if (e.message.includes('不允许传超过 100 个字符')) moveHavingToRaw(req); else throw e; }

Prevention

When it happens

Trigger: A HAVING clause like "@having": "sum(amount)>1000 and max(created_at)>'2024-01-01' and min(level)>=2 ..." whose total string exceeds 100 chars.

Common situations: Dashboards building ever-growing condition strings; concatenated dynamic filters crossing the 100-char limit only for some users; migration from hand-written SQL HAVING into @having.

Related errors


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