{"record":{"id":"da84e6640ce80870","repo":"quarkusio/quarkus","slug":"when-top-or-first-is-specified-the-query-must","errorCode":null,"errorMessage":"When 'Top' or 'First' is specified, the query must be a find query. Offending method is ${repositoryMethodDescription}.","messagePattern":"When 'Top' or 'First' is specified, the query must be a find query\\. Offending method is (.+?)\\.","errorType":"exception","errorClass":"UnableToParseMethodException","httpStatus":null,"severity":"error","filePath":"extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/MethodNameParser.java","lineNumber":112,"sourceCode":"        if (queryType == null) {\n            throw new UnableToParseMethodException(\"Method \" + repositoryMethodDescription\n                    + \" cannot be parsed. Did you forget to annotate the method with '@Query'?\");\n        }\n\n        int byIndex = methodName.indexOf(\"By\");\n        if ((byIndex == -1) || (byIndex + 2 >= methodName.length())) {\n            throw new UnableToParseMethodException(\"Method \" + repositoryMethodDescription\n                    + \" cannot be parsed as there is no proper 'By' clause in the name.\");\n        }\n\n        // handle 'Top' and 'First'\n        Integer topCount = null;\n        int minFirstOrTopIndex = Math.min(indexOfOrMaxValue(methodName, \"First\"), indexOfOrMaxValue(methodName, \"Top\"));\n        // 'First' and 'Top' could be part of a field name, so we only consider them as part of a top query\n        // if they are found before 'By'\n        if (minFirstOrTopIndex < byIndex) {\n            if (queryType != QueryType.SELECT) {\n                throw new UnableToParseMethodException(\n                        \"When 'Top' or 'First' is specified, the query must be a find query. Offending method is \"\n                                + repositoryMethodDescription + \".\");\n            }\n            try {\n                String topCountStr = methodName.substring(minFirstOrTopIndex, byIndex)\n                        .replace(\"Top\", \"\").replace(\"First\", \"\");\n                if (topCountStr.isEmpty()) {\n                    topCount = 1;\n                } else {\n                    topCount = Integer.valueOf(topCountStr);\n                }\n            } catch (Exception e) {\n                throw new UnableToParseMethodException(\n                        \"Unable to parse query with limiting results clause. Offending method is \"\n                                + repositoryMethodDescription + \".\");\n            }\n        }\n","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/MethodNameParser.java#L94-L130","documentation":"'First'/'Top' limiting keywords are only meaningful for find (SELECT) derived queries. If parse() sees First/Top before 'By' but the query type is count/delete/exists, it throws UnableToParseMethodException naming the offending method.","triggerScenarios":"Methods like `long countTop10ByActive(boolean active)` or `deleteFirstByStatus(String s)` — a First/Top keyword appears in the prefix of a non-SELECT derived query.","commonSituations":"Copy-pasting find-style limiting names onto count/delete methods; misunderstanding that limit applies only to result sets of finds; typos where a field name before 'By' contains First/Top accidentally combined with a non-select type.","solutions":["Remove Top/First from non-find methods; use @Query with setMaxResults or a subquery for limited count/delete","Change the method to a find query if limiting was intended: findTop10By...","Use an explicit @Query and Paginated/limit API instead of name-derived limiting"],"exampleFix":"// before\nlong countTop10ByActive(boolean active);\n// after\n@Query(\"select count(u) from User u where u.active = true\")\nlong countActive();","handlingStrategy":"validation","validationCode":"// First/Top only allowed on find (SELECT) queries\nboolean hasLimit = idx(methodName,\"First\") < idx(methodName,\"By\")\n                || idx(methodName,\"Top\") < idx(methodName,\"By\");\nboolean isSelect = methodName.startsWith(\"find\") || methodName.startsWith(\"get\") || methodName.startsWith(\"read\");\nif (hasLimit && !isSelect) throw new IllegalStateException(\"Top/First on non-find method: \" + methodName);","typeGuard":null,"tryCatchPattern":"// Build-time failure; remove Top/First from count/delete/exists:\n// long countByActive(boolean active);","preventionTips":["Never combine Top/First with count/delete/exists prefixes","Use @Query for limited aggregates","Keep limiting keywords only in the find-family"],"tags":["spring-data-jpa","build-time","derived-query","limit"],"backgroundTag":"unparseable-repository-method","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}