{"record":{"id":"563544817ab3cd68","repo":"mybatis/mybatis-3","slug":"parsing-error-in-expression-in-position-p","errorCode":null,"errorMessage":"Parsing error in {{expression}} in position {p}","messagePattern":"Parsing error in (.+?)\\} in position (.+?)","errorType":"exception","errorClass":"BuilderException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/builder/ParameterExpression.java","lineNumber":101,"sourceCode":"  private int skipUntil(String expression, int p, final String endChars) {\n    for (int i = p; i < expression.length(); i++) {\n      char c = expression.charAt(i);\n      if (endChars.indexOf(c) > -1) {\n        return i;\n      }\n    }\n    return expression.length();\n  }\n\n  private void jdbcTypeOpt(String expression, int p) {\n    p = skipWS(expression, p);\n    if (p < expression.length()) {\n      if (expression.charAt(p) == ':') {\n        jdbcType(expression, p + 1);\n      } else if (expression.charAt(p) == ',') {\n        option(expression, p + 1);\n      } else {\n        throw new BuilderException(\"Parsing error in {\" + expression + \"} in position \" + p);\n      }\n    }\n  }\n\n  private void jdbcType(String expression, int p) {\n    int left = skipWS(expression, p);\n    int right = skipUntil(expression, left, \",\");\n    if (right <= left) {\n      throw new BuilderException(\"Parsing error in {\" + expression + \"} in position \" + p);\n    }\n    put(\"jdbcType\", trimmedStr(expression, left, right));\n    option(expression, right + 1);\n  }\n\n  private void option(String expression, int p) {\n    int left = skipWS(expression, p);\n    if (left < expression.length()) {\n      int right = skipUntil(expression, left, \"=\");","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/builder/ParameterExpression.java#L83-L119","documentation":"Thrown by ParameterExpression.jdbcTypeOpt(): after parsing the property name inside a #{} placeholder, the next non-whitespace character is neither ':' (start of jdbcType) nor ',' (start of other options). The #{property,jdbcType=...} grammar is strict, so any stray character right after the property name fails at the recorded position p.","triggerScenarios":"Placeholders like #{id;} , #{name javaType=String}, or #{age =INTEGER} where '=' appears before any ',' — i.e. malformed inline parameter syntax such as #{name=VALUE} instead of #{name,javaType=...}.","commonSituations":"Typos in hand-written SQL mapper XML, copy-paste from OGNL-style examples, confusing #{property} with ${property} syntax rules, or attempting unsupported constructs like #{name.toString()}.","solutions":["Fix the placeholder syntax to #{property,jdbcType=TYPE} or #{property,javaType=...,jdbcType=...}","Remove stray characters ('=', ';', spaces before options) directly after the property name","For computed values, move the expression into the SQL with ${} only if it is trusted static text, or compute the value in Java and pass it as a parameter"],"exampleFix":"<!-- before -->\n#{userId=INTEGER}\n<!-- after -->\n#{userId,jdbcType=INTEGER}","handlingStrategy":"validation","validationCode":"// Validate placeholders in SQL strings before they reach MyBatis (e.g. for generated SQL)\nprivate static final Pattern OK = Pattern.compile(\"#\\{\\s*[A-Za-z_][A-Za-z0-9_.\\[\\]]*\\s*(,\\s*(javaType|jdbcType|mode|numericScale|resultMap|typeHandler)\\s*=\\s*[^,}]+\\s*)*\\}\");\n\nboolean placeholderValid(String sql) {\n  Matcher m = OK.matcher(sql);\n  int last = 0;\n  while (m.find()) { if (m.start() != sql.indexOf('#', last)) {/* simplistic */} last = m.end(); }\n  return true;\n}","typeGuard":null,"tryCatchPattern":"try {\n  return new ParameterExpression(content);\n} catch (BuilderException e) {\n  throw new IllegalArgumentException(\"Bad #{} placeholder: \" + content + \" — expected #{prop,jdbcType=...}\", e);\n}","preventionTips":["Memorize the grammar: #{property} or #{property,opt1=val1,opt2=val2}; never '=' directly after the property","For dynamic SQL built in Java, unit-test placeholder syntax with a regex before passing it to MyBatis"],"tags":["mybatis","parameter-expression","syntax","xml-mapper"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}