{"record":{"id":"6f6fc7bf07c7eb56","repo":"chinabugotech/hutool","slug":"bad-expression-we-find-but-no","errorCode":null,"errorMessage":"Bad expression '{}':{}, we find ']' but no '[' !","messagePattern":"Bad expression '(.+?)':(.+?), we find '\\]' but no '\\[' !","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hutool-core/src/main/java/cn/hutool/core/bean/BeanPath.java","lineNumber":343,"sourceCode":"\t\t\tc = expression.charAt(i);\n\t\t\tif (0 == i && '$' == c) {\n\t\t\t\t// 忽略开头的$符，表示当前对象\n\t\t\t\tisStartWith = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ('\\'' == c) {\n\t\t\t\t// 结束\n\t\t\t\tisInWrap = (false == isInWrap);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (false == isInWrap && ArrayUtil.contains(EXP_CHARS, c)) {\n\t\t\t\t// 处理边界符号\n\t\t\t\tif (CharUtil.BRACKET_END == c) {\n\t\t\t\t\t// 中括号（数字下标）结束\n\t\t\t\t\tif (false == isNumStart) {\n\t\t\t\t\t\tthrow new IllegalArgumentException(StrUtil.format(\"Bad expression '{}':{}, we find ']' but no '[' !\", expression, i));\n\t\t\t\t\t}\n\t\t\t\t\tisNumStart = false;\n\t\t\t\t\t// 中括号结束加入下标\n\t\t\t\t} else {\n\t\t\t\t\tif (isNumStart) {\n\t\t\t\t\t\t// 非结束中括号情况下发现起始中括号报错（中括号未关闭）\n\t\t\t\t\t\tthrow new IllegalArgumentException(StrUtil.format(\"Bad expression '{}':{}, we find '[' but no ']' !\", expression, i));\n\t\t\t\t\t} else if (CharUtil.BRACKET_START == c) {\n\t\t\t\t\t\t// 数字下标开始\n\t\t\t\t\t\tisNumStart = true;\n\t\t\t\t\t}\n\t\t\t\t\t// 每一个边界符之前的表达式是一个完整的KEY，开始处理KEY\n\t\t\t\t}\n\t\t\t\tif (builder.length() > 0) {\n\t\t\t\t\tlocalPatternParts.add(builder.toString());\n\t\t\t\t}\n\t\t\t\tbuilder.setLength(0);\n\t\t\t} else {","sourceCodeStart":325,"sourceCodeEnd":361,"githubUrl":"https://github.com/chinabugotech/hutool/blob/8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442/hutool-core/src/main/java/cn/hutool/core/bean/BeanPath.java#L325-L361","documentation":"BeanPath parses dotted/bracket property paths (e.g. a.b[0].c). When it encounters a closing ']' without a preceding '[' having opened an index, it rejects the expression as malformed. The throw point is the BRACKET_END branch when isNumStart is false, meaning the parser was not currently inside an index.","triggerScenarios":"Constructing BeanPath with a string like \"a].b\", \"[0]]\", or \"a[]\" style stray brackets. Any path where ']' appears before a matching '['.","commonSituations":"User-supplied property paths from config/UI that weren't validated; concatenating path fragments incorrectly (e.g. appending \"]\" unconditionally); JSON-pointer vs BeanPath syntax confusion.","solutions":["Balance brackets: every '[' must precede a matching ']' and contain a numeric index.","Validate the path with a regex or a test BeanPath construction before runtime use.","Strip stray brackets from generated/computed path strings."],"exampleFix":"// before\nBeanPath p = new BeanPath(\"items].name\");\n// after\nBeanPath p = new BeanPath(\"items[0].name\");","handlingStrategy":"validation","validationCode":"if (!path.matches(\"^[^.\\\\[\\\\]]+(\\\\.[^.\\\\[\\\\]]+)*(\\\\[\\\\d+\\\\])*$\")) throw new IllegalArgumentException(\"bad BeanPath: \" + path);","typeGuard":"static boolean validBeanPath(String p) { return p != null && p.chars().filter(c->c=='[').count() == p.chars().filter(c->c==']').count() && !p.contains(\"]\"); }","tryCatchPattern":null,"preventionTips":["Validate property paths from untrusted sources before constructing BeanPath.","Generate paths from a structured builder, not string concatenation."],"tags":["bean-path","parser","argument-validation"],"backgroundTag":null,"analyzedSha":"8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442","analyzedAt":"2026-08-14T04:01:12.892Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}