Tencent/APIJSON · error · IllegalArgumentException
字符 {fun} 不合法!预编译模式下 {example} 中 function 必须符合小写英文单词的 SQL 函数名
Error message
字符 {fun} 不合法!预编译模式下 {example} 中 function 必须符合小写英文单词的 SQL 函数名格式! What it means
When SQL_FUNCTION_MAP is null or empty (backend function allowlist not configured), parseSQLExpression falls back to StringUtil.isName(fun): the function name before '(' must be a single identifier word. This error means the allowlist is unconfigured AND the function token is not a plain name.
Source
Thrown at APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java:2562
boolean containOver = overIndex > 0 && overIndex < expression.length() - ")OVER(".length();
boolean containAgainst = againstIndex > 0 && againstIndex < expression.length() - ")AGAINST(".length();
if (containOver && containAgainst) {
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); //:contactCountView on GitHub (pinned to 5284052872)
Solutions
- Ensure the backend initializes SQL_FUNCTION_MAP (it is populated by default in the static block; verify your subclass/launcher did not skip it).
- Make the token before '(' a bare lowercase identifier.
- Send one function per ';'-item instead of merging tokens.
- For non-standard names, add them to SQL_FUNCTION_MAP server-side.
Example fix
// before (allowlist empty and token not a word)
{"User":{"@column":"my-schema.fn(id)"}}
// after
{"User":{"@column":"fn(id)"}} Defensive patterns
Strategy: try-catch
Validate before calling
const FUN=/^[A-Za-z][A-Za-z0-9_]*$/;
const tok=expr.slice(0,expr.indexOf('('));
if(!FUN.test(tok))throw new Error('function token must be a bare word'); Type guard
null
Try / catch
catch IllegalArgumentException; verify backend initialization of SQL_FUNCTION_MAP in server logs, then retry with a plain function name
Prevention
- Ensure backend static init runs (default SQL_FUNCTION_MAP is filled)
- One function per expression item
- No operators or prefixes before '('
When it happens
Trigger: Backend never called the static initializer that populates SQL_FUNCTION_MAP (or deliberately cleared it), and a client sends an expression whose token before '(' is not a plain word, e.g. "schema.fn(x)" or "fn(x)(y)". Any non-word token before '(' triggers it in this mode.
Common situations: Custom APIJSON forks that lazily initialize the allowlist; unit tests constructing AbstractSQLConfig without full static init; expressions with operators before '(' like "sum(a)+max(b)" parsed as one item.
Related errors
- 字符 {fun} 不合法!预编译模式下 {example} 中 function 必须符合小写英文单词的 SQL 函数名
- HEAD请求: 字符 {alias} 不合法!预编译模式下 @column:value 中 value里面用 , 分割的
- HEAD请求: 字符{origin} 不合法!预编译模式下 @column:value 中 value里面用 , 分割的
- HEAD请求: 字符 {origin.substring(0, start)} 不合法!预编译模式下 @column:v
- POST 请求必须在Table内设置要保存的 key:value !
AI-assisted analysis of Tencent/APIJSON@5284052872 (2026-08-14).
Data as JSON: /api/errors/aed1f6d9c3ecd6c9.
Report an issue: GitHub.