{"record":{"id":"eedbb7762901463f","repo":"Tencent/APIJSON","slug":"combine-eedbb7","errorCode":null,"errorMessage":"{}:{ @combine:'{}' } 中字符 '{}' 不合法！左括号 ( 比 右括号 ) 少！数量必须相等从而完整闭合 (...) ！","messagePattern":"(.+?):(.+?)' \\} 中字符 '(.+?)' 不合法！左括号 \\( 比 右括号 \\) 少！数量必须相等从而完整闭合 \\(\\.\\.\\.\\) ！","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java","lineNumber":3633,"sourceCode":"\t\t\t\t\t\tthrow new IllegalArgumentException(errPrefix + \" 中字符 '\" + s.substring(i)\n\t\t\t\t\t\t+ \"' 不合法！左边缺少 & | 逻辑连接符！逻辑连接符 & | 左右必须各一个相邻空格！空格不能多也不能少！\"\n\t\t\t\t\t\t+ \"不允许首尾有空格，也不允许连续空格！左括号 ( 的右边 和 右括号 ) 的左边 都不允许有相邻空格！\");\n\t\t\t\t\t}\n\n\t\t\t\t\tdepth ++;\n\t\t\t\t\tif (depth > maxDepth && maxDepth > 0) {\n\t\t\t\t\t\tthrow new IllegalArgumentException(errPrefix + \" 中字符 '\" + s.substring(0, i + 1)\n\t\t\t\t\t\t+ \"' 不合法！括号 (()) 嵌套层级 \" + depth + \" 已超过最大值，必须在 0-\" + maxDepth + \" 内！\");\n\t\t\t\t\t}\n\n\t\t\t\t\tresult += c;\n\t\t\t\t\tlastLogic = 0;\n\t\t\t\t\tfirst = true;\n\t\t\t\t}\n\t\t\t\telse if (c == ')') {\n\t\t\t\t\tdepth --;\n\t\t\t\t\tif (depth < 0) {\n\t\t\t\t\t\tthrow new IllegalArgumentException(errPrefix + \" 中字符 '\" + s.substring(0, i + 1)\n\t\t\t\t\t\t+ \"' 不合法！左括号 ( 比 右括号 ) 少！数量必须相等从而完整闭合 (...) ！\");\n\t\t\t\t\t}\n\n\t\t\t\t\tresult += c;\n\t\t\t\t\tlastLogic = 0;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tkey += c;\n\t\t\t\t}\n\n\t\t\t\tlast = c;\n\t\t\t\ti ++;\n\t\t\t}\n\n\t\t\tif (depth != 0) {\n\t\t\t\tthrow new IllegalArgumentException(errPrefix + \" 中字符 '\" + s\n\t\t\t\t\t\t+ \"' 不合法！左括号 ( 比 右括号 ) 多！数量必须相等从而完整闭合 (...) ！\");\n\t\t\t}","sourceCodeStart":3615,"sourceCodeEnd":3651,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java#L3615-L3651","documentation":"Thrown while parsing @combine when a ')' is encountered but depth is already 0 — i.e. there are more ')' than '('. The parser decrements depth on each ')' and rejects negative depth immediately because the expression cannot form a well-formed boolean condition.","triggerScenarios":"@combine values like \"a) & b\" or \"(a & b))\" — any expression where a closing parenthesis appears without a matching preceding '('.","commonSituations":"Hand-written or programmatically concatenated combine strings that drop or duplicate a parenthesis; UI query-builder bugs emitting unbalanced strings.","solutions":["Balance the parentheses in @combine so every ')' has a matching earlier '('.","If the string is generated by client code, add a stack/balance check before sending the request.","Simplify the expression and rebuild it group by group."],"exampleFix":"// before\n{\"@combine\": \"a & b) | c\"}\n// after\n{\"@combine\": \"(a & b) | c\"}","handlingStrategy":"validation","validationCode":"function balanced(s) { let d = 0; for (const c of s) { if (c === '(') d++; if (c === ')') { d--; if (d < 0) return false; } } return d === 0; }\nif (!balanced(combineStr)) throw new Error('unbalanced @combine');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always run a balance check on generated combine strings.","Use a builder API that appends groups as ( inner ) units rather than raw string concatenation."],"tags":["apijson","combine","unbalanced-parens","validation"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}