Tencent/APIJSON · error · IllegalArgumentException

字符 {fun} 不合法!预编译模式下 {example} 中 function 必须符合小写英文单词的 SQL 函数名

Error message

字符 {fun} 不合法!预编译模式下 {example} 中 function 必须符合小写英文单词的 SQL 函数名格式!且必须是后端允许调用的 SQL 函数!

What it means

parseSQLExpression enforces a function allowlist: when SQL_FUNCTION_MAP is populated (the default), any function name before '(' that is not a key in that map is rejected with this message naming the offending token. Only backend-approved SQL functions may appear in client expressions.

Source

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

				throw new IllegalArgumentException("字符 " + expression + " 不合法!预编译模式下 " + example
						+ " 中 function 必须符合小写英文单词的 SQL 函数名格式!不能同时存在窗口函数关键词 OVER 和全文索引关键词 AGAINST!");
			}

			if (containOver == false && containAgainst == false) {
				int end = expression.lastIndexOf(')');
				if (start >= end) {
					throw new IllegalArgumentException("字符 " + expression + " 不合法!"
							+ key + ":value 中 value 里的 SQL函数必须为 function(arg0,arg1,...) 这种格式!");
				}
				String fun = expression.substring(0, start);
				if (fun.isEmpty() == false) {
					if (SQL_FUNCTION_MAP == null || SQL_FUNCTION_MAP.isEmpty()) {
						if (StringUtil.isName(fun) == false) {
							throw new IllegalArgumentException("字符 " + fun + " 不合法!预编译模式下 " + example
									+ " 中 function 必须符合小写英文单词的 SQL 函数名格式!");
						}
					} else if (SQL_FUNCTION_MAP.containsKey(fun) == false) {
						throw new IllegalArgumentException("字符 " + fun + " 不合法!预编译模式下 " + example
								+ " 中 function 必须符合小写英文单词的 SQL 函数名格式!且必须是后端允许调用的 SQL 函数!");
					}
				}

				String s = expression.substring(start + 1, end);
				boolean distinct = s.startsWith(PREFIX_DISTINCT);
				if (distinct) {
					s = s.substring(PREFIX_DISTINCT.length());
				}

				// 解析函数内的参数
				String ckeys[] = parseArgsSplitWithComma(s, false, containRaw, allowAlias);

				String suffix = expression.substring(end + 1); //:contactCount
				String alias = null;
				if (allowAlias) {
					int index = suffix.lastIndexOf(":");
					alias = index < 0 ? "" : suffix.substring(index + 1); //contactCount

View on GitHub (pinned to 5284052872)

Solutions

  1. Use a function already in the default map (count/sum/max/min/avg/date_format/concat/...).
  2. Ask the backend administrator to add the function to SQL_FUNCTION_MAP (AbstractSQLConfig static block or your SQLConfig subclass).
  3. Re-express the computation with allowed primitives or compute client-side.
  4. Define the whole expression as a @raw entry server-side.

Example fix

// before
{"User":{"@column":"ifnull(name,'x')"}}
// after — server adds SQL_FUNCTION_MAP.put("ifnull", ""); then the same request succeeds
{"User":{"@column":"ifnull(name,'x')"}}
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED = new Set(['count','sum','max','min','avg','date_format','concat' /* mirror backend SQL_FUNCTION_MAP */]);
const fn = expr.slice(0, expr.indexOf('('));
if (!ALLOWED.has(fn)) throw new Error('function not allowed: ' + fn);

Type guard

function isAllowedFn(e, allow) { const i = e.indexOf('('); return i > 0 && allow.has(e.slice(0, i)); }

Try / catch

catch IllegalArgumentException mentioning backend allowlist; report to backend admin to whitelist or rewrite with allowed functions

Prevention

When it happens

Trigger: "@column":"ifnull(name,'x')" where 'ifnull' was not added to SQL_FUNCTION_MAP; "@column":"version()"; any DB-specific function the backend administrator did not whitelist; also sending a differently-cased key than the exact registered one.

Common situations: Frontend uses a MySQL function the default map lacks (e.g. database-specific or new-in-8.0 functions); after upgrading APIJSON the map contents changed; multi-DB deployments where one DB's function is not registered for the other.

Related errors


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