{"record":{"id":"e881fc99b2ccac85","repo":"quarkusio/quarkus","slug":"method-name-of-repository-repositoryclassin-e881fc","errorCode":null,"errorMessage":"${method.name()} of Repository ${repositoryClassInfo} is meant to be a delete query and can therefore only have a void or long return type","messagePattern":"(.+?) of Repository (.+?) is meant to be a delete query and can therefore only have a void or long return type","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/CustomQueryMethodsAdder.java","lineNumber":228,"sourceCode":"                for (int i = 0; i < methodParameterTypes.size(); i++) {\n                    params[i] = mc.parameter(\"p\" + i);\n                }\n\n                mc.body(bc -> {\n                    // Store static field and instance field in LocalVars so they can be reused\n                    LocalVar ops = bc.localVar(\"ops\", bc.getStaticField(operationsField));\n                    LocalVar entityClass = bc.localVar(\"entityClass\",\n                            bc.get(mc.this_().field(entityClassFieldDescriptor)));\n\n                    if (isModifying) {\n                        AnnotationInstance modifyingAnnotation = method.annotation(DotNames.SPRING_DATA_MODIFYING);\n                        handleFlushAutomatically(modifyingAnnotation, bc, entityClass);\n\n                        if (finalQueryString.toLowerCase().startsWith(\"delete\")) {\n                            if (!DotNames.PRIMITIVE_LONG.equals(methodReturnTypeDotName)\n                                    && !DotNames.LONG.equals(methodReturnTypeDotName)\n                                    && !DotNames.VOID.equals(methodReturnTypeDotName)) {\n                                throw new IllegalArgumentException(\n                                        method.name() + \" of Repository \" + repositoryClassInfo\n                                                + \" is meant to be a delete query and can therefore only have a void or long return type\");\n                            }\n\n                            // we need to strip 'delete' or else JpaOperations.delete will generate the wrong query\n                            String deleteQueryString = finalQueryString.substring(\"delete\".length());\n                            Expr deleteCount;\n                            if (!finalNamedParameterToIndex.isEmpty()) {\n                                Expr parameters = generateParametersObject(finalNamedParameterToIndex, bc, params);\n\n                                // call JpaOperations.delete\n                                deleteCount = bc.invokeVirtual(\n                                        MethodDesc.of(AbstractManagedJpaOperations.class, \"delete\", long.class,\n                                                Class.class, String.class, Parameters.class),\n                                        ops, entityClass,\n                                        Const.of(deleteQueryString), parameters);\n                            } else {\n                                Expr paramsArray = generateParamsArray(queryParameterIndexes, bc, params);","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/CustomQueryMethodsAdder.java#L210-L246","documentation":"A @Modifying query starting with 'delete' maps to JpaOperations.delete and may only return void, long, or java.lang.Long (the affected row count). Any other declared return type is rejected at build time with this IllegalArgumentException because there is no way to materialize other result shapes from a delete statement.","triggerScenarios":"A repository method with @Query(\"delete ...\") (with or without @Modifying) declared to return int, Integer, boolean, List<T>, an entity type, or any type other than long/Long/void.","commonSituations":"Porting from JPA's executeUpdate() which returns int and declaring int in the repository; copy-pasting a select method signature; Spring allows int/Integer there while Quarkus's Spring Data layer is more restrictive and requires long/Long/void.","solutions":["Change the return type to long, Long, or void","Replace int/Integer with long/Long (Quarkus does not accept int for delete counts here)","If no count is needed, declare void and ignore the return value","Split the method: do a paginated/select query separately, then a void delete"],"exampleFix":"// before\n@Modifying\n@Query(\"delete from Token t where t.expiry < :now\")\nint deleteExpired(Instant now);\n// after\n@Modifying\n@Query(\"delete from Token t where t.expiry < :now\")\nlong deleteExpired(Instant now);","handlingStrategy":"validation","validationCode":"if (query.trim().toLowerCase().startsWith(\"delete\")) {\n    Class<?> rt = method.getReturnType();\n    if (!(rt.equals(void.class) || rt.equals(long.class) || rt.equals(Long.class)))\n        throw new IllegalArgumentException(\"Delete @Query must return void or long/Long\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    compile();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"delete query and can therefore only have\")) {\n        log.error(\"Change return type to long/Long/void\");\n    }\n    throw e;\n}","preventionTips":["Declare delete @Query methods as long, Long, or void only","Do not copy int-returning executeUpdate signatures into repositories","Use void when the count is not needed","Review return types when migrating between frameworks"],"tags":["spring-data-jpa","quarkus","delete-query","return-type","build-time"],"backgroundTag":"delete-query-return-type-restricted","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}