mybatis/mybatis-3 · error · BuilderException

Parsing error was found in mapping #{{content}}. Check synt

Error message

Parsing error was found in mapping #{{content}}.  Check syntax #{property|(expression), var1=value1, var2=value2, ...} 

What it means

A generic wrapper in ParameterMappingTokenHandler.parseParameterMapping(): new ParameterExpression(content) threw something other than a BuilderException (e.g. StringIndexOutOfBoundsException from malformed input), which is rethrown as a BuilderException with a hint showing the expected #{property,(expression),var1=value1,...} syntax and the original exception as cause.

Source

Thrown at src/main/java/org/apache/ibatis/builder/ParameterMappingTokenHandler.java:192

    if (Map.class.isAssignableFrom(parameterType)) {
      return Object.class;
    }
    MetaClass metaClass = MetaClass.forClass(parameterType, configuration.getReflectorFactory());
    if (metaClass.hasGetter(property)) {
      Entry<Type, Class<?>> getterType = metaClass.getGenericGetterType(property);
      genericType = getterType.getKey();
      return getterType.getValue();
    }
    return Object.class;
  }

  private Map<String, String> parseParameterMapping(String content) {
    try {
      return new ParameterExpression(content);
    } catch (BuilderException ex) {
      throw ex;
    } catch (Exception ex) {
      throw new BuilderException("Parsing error was found in mapping #{" + content
          + "}.  Check syntax #{property|(expression), var1=value1, var2=value2, ...} ", ex);
    }
  }
}

View on GitHub (pinned to 008069adb1)

Solutions

  1. Inspect the exact content shown in the message and fix the placeholder to #{property} or #{property,opt=val}
  2. If SQL is generated, add a unit test asserting generated placeholders match /#\{[^}]+}/ and never emit empty or leading-comma placeholders
  3. Log the cause exception — its stack trace pinpoints the parse step that choked

Example fix

-- before (generated SQL fragment)
WHERE id = #{}
-- after
WHERE id = #{id}
Defensive patterns

Strategy: try-catch

Validate before calling

// Sanity-check generated SQL placeholders before creating the statement
for (String ph : extractPlaceholders(sql)) { // regex /#\{([^}]*)\}/
  if (ph.isBlank() || ph.startsWith(",") || ph.endsWith(",") || ph.contains("=,") || ph.contains("=}")) {
    throw new IllegalArgumentException("Malformed placeholder #{" + ph + "} in generated SQL");
  }
}

Try / catch

try {
  configuration.addMappedStatement(...);
} catch (BuilderException e) {
  Throwable cause = e.getCause();
  log.error("Placeholder parse failed for: {} (cause: {})", content, cause);
  throw e; // configuration errors must not be swallowed
}

Prevention

When it happens

Trigger: Severely malformed placeholders such as #{}, #{,}, #{a,b=} that crash the low-level parser instead of producing a clean BuilderException; unbalanced separators or empty segments.

Common situations: Programmatically generated SQL concatenating user input into #{} placeholders; template engines (FreeMarker/Velocity) emitting broken placeholder text; edge-case inputs the hand-written recursive-descent parser does not guard.

Related errors


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/5b0b3ed1db7d8def. Report an issue: GitHub.