{"record":{"id":"69a08c75b35894c9","repo":"mybatis/mybatis-3","slug":"expected-one-result-or-null-to-be-returned-by-se","errorCode":null,"errorMessage":"Expected one result (or null) to be returned by selectOne(), but found: \" + list.size()","messagePattern":"Expected one result \\(or null\\) to be returned by selectOne\\(\\), but found: \" \\+ list\\.size\\(\\)","errorType":"exception","errorClass":"TooManyResultsException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/session/defaults/DefaultSqlSession.java","lineNumber":79,"sourceCode":"\n  public DefaultSqlSession(Configuration configuration, Executor executor) {\n    this(configuration, executor, false);\n  }\n\n  @Override\n  public <T> T selectOne(String statement) {\n    return this.selectOne(statement, null);\n  }\n\n  @Override\n  public <T> T selectOne(String statement, Object parameter) {\n    // Popular vote was to return null on 0 results and throw exception on too many.\n    List<T> list = this.selectList(statement, parameter);\n    if (list.size() == 1) {\n      return list.get(0);\n    }\n    if (list.size() > 1) {\n      throw new TooManyResultsException(\n          \"Expected one result (or null) to be returned by selectOne(), but found: \" + list.size());\n    } else {\n      return null;\n    }\n  }\n\n  @Override\n  public <K, V> Map<K, V> selectMap(String statement, String mapKey) {\n    return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);\n  }\n\n  @Override\n  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {\n    return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);\n  }\n\n  @Override\n  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/session/defaults/DefaultSqlSession.java#L61-L97","documentation":"DefaultSqlSession.selectOne() runs the query as a list and, by explicit design decision (the comment records 'popular vote'), returns null for zero rows but throws TooManyResultsException when more than one row comes back. The contract is at-most-one: the statement was expected to match a single record but the database returned several.","triggerScenarios":"selectOne()/sqlSession.selectOne(statement, param) where the WHERE clause matches multiple rows: non-unique filter column, missing AND condition, LIKE filters, joins fan-out duplicating rows; also mapper interface methods returning a single object whose SQL lacks a LIMIT/unique key.","commonSituations":"Querying by a non-unique column (username, status); data drift inserting duplicate rows where uniqueness was assumed; dynamic <if> conditions all skipping so the query degrades to SELECT ... without WHERE; pagination removed during refactoring.","solutions":["Tighten the WHERE clause with a unique key or add missing conditions so at most one row matches.","If multiple rows are legitimate, switch to selectList() and take the first row explicitly (or return List<T> from the mapper).","Clean duplicate rows and add a unique constraint where business rules say the field is unique.","Add LIMIT 1 / FETCH FIRST 1 ROWS ONLY only if any-row semantics are acceptable."],"exampleFix":"// before\nUser findByName(String name);  <!-- SELECT * FROM users WHERE name = #{name} -->\n// after\nList<User> findByName(String name);  <!-- same SQL, caller decides -->\n// or ensure uniqueness:\n<!-- SELECT * FROM users WHERE id = #{id} -->","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { User u = mapper.findByName(name); }\ncatch (TooManyResultsException e) {\n  List<User> all = mapper.findByNameList(name); // fall back to list variant\n  return all.get(0); // or apply real selection logic\n}","preventionTips":["Use selectOne only with unique-key predicates (id, unique index columns).","Return List<T> from mappers whenever uniqueness is not guaranteed by a constraint.","Add DB unique constraints for fields you query single-row by."],"tags":["mybatis","query","too-many-results","select-one"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}