{"record":{"id":"5b0b3ed1db7d8def","repo":"mybatis/mybatis-3","slug":"parsing-error-was-found-in-mapping-content","errorCode":null,"errorMessage":"Parsing error was found in mapping #{{content}}.  Check syntax #{property|(expression), var1=value1, var2=value2, ...} ","messagePattern":"Parsing error was found in mapping #(.+?)\\}\\.  Check syntax #(.+?) ","errorType":"exception","errorClass":"BuilderException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/builder/ParameterMappingTokenHandler.java","lineNumber":192,"sourceCode":"    if (Map.class.isAssignableFrom(parameterType)) {\n      return Object.class;\n    }\n    MetaClass metaClass = MetaClass.forClass(parameterType, configuration.getReflectorFactory());\n    if (metaClass.hasGetter(property)) {\n      Entry<Type, Class<?>> getterType = metaClass.getGenericGetterType(property);\n      genericType = getterType.getKey();\n      return getterType.getValue();\n    }\n    return Object.class;\n  }\n\n  private Map<String, String> parseParameterMapping(String content) {\n    try {\n      return new ParameterExpression(content);\n    } catch (BuilderException ex) {\n      throw ex;\n    } catch (Exception ex) {\n      throw new BuilderException(\"Parsing error was found in mapping #{\" + content\n          + \"}.  Check syntax #{property|(expression), var1=value1, var2=value2, ...} \", ex);\n    }\n  }\n}\n","sourceCodeStart":174,"sourceCodeEnd":197,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/builder/ParameterMappingTokenHandler.java#L174-L197","documentation":"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.","triggerScenarios":"Severely malformed placeholders such as #{}, #{,}, #{a,b=} that crash the low-level parser instead of producing a clean BuilderException; unbalanced separators or empty segments.","commonSituations":"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.","solutions":["Inspect the exact content shown in the message and fix the placeholder to #{property} or #{property,opt=val}","If SQL is generated, add a unit test asserting generated placeholders match /#\\{[^}]+}/ and never emit empty or leading-comma placeholders","Log the cause exception — its stack trace pinpoints the parse step that choked"],"exampleFix":"-- before (generated SQL fragment)\nWHERE id = #{}\n-- after\nWHERE id = #{id}","handlingStrategy":"try-catch","validationCode":"// Sanity-check generated SQL placeholders before creating the statement\nfor (String ph : extractPlaceholders(sql)) { // regex /#\\{([^}]*)\\}/\n  if (ph.isBlank() || ph.startsWith(\",\") || ph.endsWith(\",\") || ph.contains(\"=,\") || ph.contains(\"=}\")) {\n    throw new IllegalArgumentException(\"Malformed placeholder #{\" + ph + \"} in generated SQL\");\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  configuration.addMappedStatement(...);\n} catch (BuilderException e) {\n  Throwable cause = e.getCause();\n  log.error(\"Placeholder parse failed for: {} (cause: {})\", content, cause);\n  throw e; // configuration errors must not be swallowed\n}","preventionTips":["Never build #{} placeholders by string concatenation of user input — pass bound parameters instead","Template-generated SQL should round-trip through a placeholder validator in unit tests"],"tags":["mybatis","parameter-expression","syntax","dynamic-sql"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}