{"record":{"id":"7f8e3094509babf5","repo":"mybatis/mybatis-3","slug":"parameter-key-not-found-available-parameters","errorCode":null,"errorMessage":"Parameter '{key}' not found. Available parameters are {keySet}","messagePattern":"Parameter '(.+?)' not found\\. Available parameters are (.+?)","errorType":"exception","errorClass":"BindingException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/binding/MapperMethod.java","lineNumber":210,"sourceCode":"    Map<K, V> result;\n    Object param = method.convertArgsToSqlCommandParam(args);\n    if (method.hasRowBounds()) {\n      RowBounds rowBounds = method.extractRowBounds(args);\n      result = sqlSession.selectMap(command.getName(), param, method.getMapKey(), rowBounds);\n    } else {\n      result = sqlSession.selectMap(command.getName(), param, method.getMapKey());\n    }\n    return result;\n  }\n\n  public static class ParamMap<V> extends HashMap<String, V> {\n\n    private static final long serialVersionUID = -2212268410512043556L;\n\n    @Override\n    public V get(Object key) {\n      if (!super.containsKey(key)) {\n        throw new BindingException(\"Parameter '\" + key + \"' not found. Available parameters are \" + keySet());\n      }\n      return super.get(key);\n    }\n\n  }\n\n  public static class SqlCommand {\n\n    private final String name;\n    private final SqlCommandType type;\n\n    public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {\n      final String methodName = method.getName();\n      final Class<?> declaringClass = method.getDeclaringClass();\n      MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass, configuration);\n      if (ms == null) {\n        if (method.getAnnotation(Flush.class) == null) {\n          throw new BindingException(","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/binding/MapperMethod.java#L192-L228","documentation":"ParamMap.get() is the strict parameter map MyBatis uses for named parameter lookup in SQL (#{...}). Unlike a plain HashMap it throws when the key is absent, so typos in a #{} placeholder or misuse of @Param names produce this precise diagnostic listing the actually available keys.","triggerScenarios":"SQL contains #{userId} but the method declares @Param(\"id\") or no @Param at all; referencing #{param1} style names when actual names differ; OGNL navigation on a property that does not exist on the single POJO parameter (e.g. #{user.name} when the parameter has no 'user' field); a nested association referencing a property not present in the row object.","commonSituations":"Renaming a Java parameter or @Param without updating the XML; copy-pasting SQL between mappers with different parameter names; multiple parameters without @Param annotations (available names become arg0/param1 style).","solutions":["Read the 'Available parameters are [...]' list in the message and use one of those names in #{}","Add or correct @Param(\"...\") on the mapper method parameter to match the placeholder","For multiple parameters, annotate every parameter with @Param explicitly"],"exampleFix":"<!-- before -->\nUser find(@Param(\"id\") Long id);\nSELECT * FROM users WHERE user_id = #{userId}\n<!-- after -->\nUser find(@Param(\"userId\") Long id);\nSELECT * FROM users WHERE user_id = #{userId}","handlingStrategy":"validation","validationCode":"Object[] args = ...; // before calling\n// with @Param names known, verify placeholders exist in the ParamMap once in tests:\n// MapperMethod.ParamMap#get throws; guard by checking containsKey in a custom wrapper if needed.","typeGuard":null,"tryCatchPattern":"catch (PersistenceException e) { Throwable c = e.getCause(); if (c instanceof BindingException && c.getMessage().contains(\"not found. Available parameters\")) { /* surface available list to developer */ } throw e; }","preventionTips":["Annotate every multi-parameter mapper method with @Param and mirror names in #{}","Add a CI test that parses each mapper XML against its interface (mybatis catches drift at first call otherwise)","Prefer consistent naming: parameter name = SQL placeholder name"],"tags":["mybatis","binding","parameters","param-annotation"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}