{"record":{"id":"e9406e769b087b91","repo":"quarkusio/quarkus","slug":"currently-spring-cache-annotations-can-only-be-add","errorCode":null,"errorMessage":"Currently Spring Cache annotations can only be added to methods. Offending instance is annotation ' + instance + ' on  + instance.target() + '","messagePattern":"Currently Spring Cache annotations can only be added to methods\\. Offending instance is annotation ' \\+ instance \\+ ' on  \\+ instance\\.target\\(\\) \\+ '","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/spring-cache/deployment/src/main/java/io/quarkus/spring/cache/SpringCacheProcessor.java","lineNumber":75,"sourceCode":"            Collection<AnnotationInstance> instances = combinedIndex.getIndex().getAnnotations(cacheAnnotation);\n            for (AnnotationInstance instance : instances) {\n                validateUsage(instance);\n                Optional<String> cacheName = getSpringCacheName(instance);\n                if (cacheName.isPresent()) {\n                    cacheNames.add(cacheName.get());\n                }\n            }\n        }\n        List<AdditionalCacheNameBuildItem> result = new ArrayList<>(cacheNames.size());\n        for (String cacheName : cacheNames) {\n            result.add(new AdditionalCacheNameBuildItem(cacheName));\n        }\n        return result;\n    }\n\n    private void validateUsage(AnnotationInstance instance) {\n        if (instance.target().kind() != AnnotationTarget.Kind.METHOD) {\n            throw new IllegalArgumentException(\n                    \"Currently Spring Cache annotations can only be added to methods. Offending instance is annotation '\"\n                            + instance + \"' on \" + instance.target() + \"'\");\n        }\n        List<AnnotationValue> values = instance.values();\n        List<String> unsupportedValues = new ArrayList<>();\n        for (AnnotationValue value : values) {\n            if (CURRENTLY_UNSUPPORTED_ANNOTATION_VALUES.contains(value.name())) {\n                unsupportedValues.add(value.name());\n            }\n        }\n        if (!unsupportedValues.isEmpty()) {\n            throw new IllegalArgumentException(\"Annotation '\" +\n                    instance + \"' on '\" + instance.target()\n                    + \"' contains the following currently unsupported annotation values: \"\n                    + String.join(\", \", unsupportedValues));\n        }\n    }\n","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-cache/deployment/src/main/java/io/quarkus/spring/cache/SpringCacheProcessor.java#L57-L93","documentation":"Quarkus's Spring Cache extension processes @Cacheable/@CacheEvict/@CachePut annotations at build time and only supports method-level placement, unlike Spring which also honors class-level annotations. During deployment, validateUsage inspects each annotation instance and throws when its Jandex target kind is not METHOD. The build fails immediately so misannotated code is caught before runtime.","triggerScenarios":"Placing @Cacheable, @CachePut, or @CacheEvict on a class, interface, field, or parameter instead of a method in a Quarkus application; the annotation is then indexed as a non-METHOD AnnotationTarget and cacheNames() -> validateUsage() throws during augmentation.","commonSituations":"Porting a Spring Boot app where class-level @Cacheable was legal; developers copying Spring examples that annotate the class to apply caching to all methods.","solutions":["Move the annotation from the class/field onto each concrete public method you want cached","If you intended class-wide caching, annotate every relevant method explicitly","Remove the annotation from interfaces/parameters entirely"],"exampleFix":"// before\n@Cacheable(\"items\")\npublic class ItemService { ... }\n\n// after\npublic class ItemService {\n    @Cacheable(\"items\")\n    public Item find(long id) { ... }\n}","handlingStrategy":"validation","validationCode":"if (!method.isAnnotationPresent(Cacheable.class)) return;\n// ensure annotation only on methods:\nif (this.getClass().getAnnotation(Cacheable.class) != null)\n    throw new IllegalStateException(\"@Cacheable must be on methods, not the class\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never place @Cacheable/@CachePut/@CacheEvict on classes or interfaces in Quarkus","Annotate concrete bean methods only","Check the Quarkus Spring Cache guide for supported attributes before porting Spring code"],"tags":["quarkus","spring-cache","build-time","annotation-placement"],"backgroundTag":"unsupported-annotation-target","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"}