chinabugotech/hutool · error · IllegalArgumentException

Bad expression '{}':{}, we find ']' but no '[' !

Error message

Bad expression '{}':{}, we find ']' but no '[' !

What it means

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.

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/bean/BeanPath.java:343

			c = expression.charAt(i);
			if (0 == i && '$' == c) {
				// 忽略开头的$符,表示当前对象
				isStartWith = true;
				continue;
			}

			if ('\'' == c) {
				// 结束
				isInWrap = (false == isInWrap);
				continue;
			}

			if (false == isInWrap && ArrayUtil.contains(EXP_CHARS, c)) {
				// 处理边界符号
				if (CharUtil.BRACKET_END == c) {
					// 中括号(数字下标)结束
					if (false == isNumStart) {
						throw new IllegalArgumentException(StrUtil.format("Bad expression '{}':{}, we find ']' but no '[' !", expression, i));
					}
					isNumStart = false;
					// 中括号结束加入下标
				} else {
					if (isNumStart) {
						// 非结束中括号情况下发现起始中括号报错(中括号未关闭)
						throw new IllegalArgumentException(StrUtil.format("Bad expression '{}':{}, we find '[' but no ']' !", expression, i));
					} else if (CharUtil.BRACKET_START == c) {
						// 数字下标开始
						isNumStart = true;
					}
					// 每一个边界符之前的表达式是一个完整的KEY,开始处理KEY
				}
				if (builder.length() > 0) {
					localPatternParts.add(builder.toString());
				}
				builder.setLength(0);
			} else {

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Balance brackets: every '[' must precede a matching ']' and contain a numeric index.
  2. Validate the path with a regex or a test BeanPath construction before runtime use.
  3. Strip stray brackets from generated/computed path strings.

Example fix

// before
BeanPath p = new BeanPath("items].name");
// after
BeanPath p = new BeanPath("items[0].name");
Defensive patterns

Strategy: validation

Validate before calling

if (!path.matches("^[^.\\[\\]]+(\\.[^.\\[\\]]+)*(\\[\\d+\\])*$")) throw new IllegalArgumentException("bad BeanPath: " + path);

Type guard

static boolean validBeanPath(String p) { return p != null && p.chars().filter(c->c=='[').count() == p.chars().filter(c->c==']').count() && !p.contains("]"); }

Prevention

When it happens

Trigger: Constructing BeanPath with a string like "a].b", "[0]]", or "a[]" style stray brackets. Any path where ']' appears before a matching '['.

Common situations: 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.

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/6f6fc7bf07c7eb56. Report an issue: GitHub.