{"record":{"id":"1772528ca213a91a","repo":"mybatis/mybatis-3","slug":"selectkey-returned-no-data","errorCode":null,"errorMessage":"SelectKey returned no data.","messagePattern":"SelectKey returned no data\\.","errorType":"exception","errorClass":"ExecutorException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/executor/keygen/SelectKeyGenerator.java","lineNumber":69,"sourceCode":"  @Override\n  public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {\n    if (!executeBefore) {\n      processGeneratedKeys(executor, ms, parameter);\n    }\n  }\n\n  private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {\n    try {\n      if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {\n        String[] keyProperties = keyStatement.getKeyProperties();\n        final Configuration configuration = ms.getConfiguration();\n        final MetaObject metaParam = configuration.newMetaObject(parameter);\n        // Do not close keyExecutor.\n        // The transaction will be closed by parent executor.\n        Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);\n        List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);\n        if (values.isEmpty()) {\n          throw new ExecutorException(\"SelectKey returned no data.\");\n        }\n        if (values.size() > 1) {\n          throw new ExecutorException(\"SelectKey returned more than one value.\");\n        } else {\n          MetaObject metaResult = configuration.newMetaObject(values.get(0));\n          if (keyProperties.length == 1) {\n            if (metaResult.hasGetter(keyProperties[0])) {\n              setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));\n            } else {\n              // no getter for the property - maybe just a single value object\n              // so try that\n              setValue(metaParam, keyProperties[0], values.get(0));\n            }\n          } else {\n            handleMultipleProperties(keyProperties, metaParam, metaResult);\n          }\n        }\n      }","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/executor/keygen/SelectKeyGenerator.java#L51-L87","documentation":"SelectKeyGenerator runs the <selectKey> statement (before or after the insert) and expects it to return exactly one row containing the key value. An empty result means no key could be obtained, so MyBatis throws this ExecutorException instead of silently leaving the keyProperty unset.","triggerScenarios":"A <selectKey> whose SQL returns no rows for the current input, e.g. SELECT seq.NEXTVAL FROM DUAL on an exhausted/broken sequence, a lookup query (SELECT id FROM t WHERE ...) matching nothing, or a statement type misconfigured as a query returning void.","commonSituations":"Oracle/PostgreSQL sequence selects when the sequence object is missing or renamed; MAX(id)+1 strategies on empty tables with a WHERE filter; resultType on selectKey missing so the row maps to null.","solutions":["Run the selectKey SQL manually with the same parameters to see why it returns zero rows","Ensure the sequence/table referenced by the selectKey exists and is queryable in that environment","Add a resultType/resultMap to the <selectKey> so the row is actually materialized","Guarantee the selectKey SQL always returns exactly one row (e.g. FROM DUAL / LIMIT 1)"],"exampleFix":"<!-- before: returns 0 rows on empty table -->\n<selectKey keyProperty=\"id\" resultType=\"long\" order=\"BEFORE\">\n  SELECT MAX(id)+1 FROM users WHERE tenant = #{tenant}\n</selectKey>\n\n<!-- after: always one row -->\n<selectKey keyProperty=\"id\" resultType=\"long\" order=\"BEFORE\">\n  SELECT nextval('user_seq')\n</selectKey>","handlingStrategy":"validation","validationCode":"// Smoke-test the selectKey SQL during app startup in the target schema\nLong key = jdbcTemplate.queryForObject(\"SELECT nextval('user_seq')\", Long.class);\nif (key == null) throw new IllegalStateException(\"selectKey source is not returning rows\");","typeGuard":null,"tryCatchPattern":"try { mapper.insert(user); } catch (PersistenceException e) { if (String.valueOf(e.getMessage()).contains(\"SelectKey returned no data\")) { log.error(\"selectKey SQL returned 0 rows — verify sequence/table\"); } throw e; }","preventionTips":["Always give <selectKey> a resultType and a statement that provably returns one row","Run the selectKey SQL in CI against a real schema"],"tags":["selectkey","insert","sequence"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}