{"record":{"id":"2d0520c2391dcd66","repo":"projectlombok/lombok","slug":"not-an-annotation-type-target","errorCode":null,"errorMessage":"Not an annotation type: <target>","messagePattern":"Not an annotation type: <target>","errorType":"exception","errorClass":"ClassCastException","httpStatus":null,"severity":"error","filePath":"src/utils/lombok/core/SpiLoadUtil.java","lineNumber":193,"sourceCode":"\t\t\tif (potential != null) return potential;\n\t\t}\n\t\t\n\t\treturn null;\n\t}\n\t\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static Class<? extends Annotation> findAnnotationHelper(Class<?> base, Type iface) {\n\t\tif (iface instanceof ParameterizedType) {\n\t\t\tParameterizedType p = (ParameterizedType)iface;\n\t\t\tif (!base.equals(p.getRawType())) return null;\n\t\t\tType target = p.getActualTypeArguments()[0];\n\t\t\tif (target instanceof Class<?>) {\n\t\t\t\tif (Annotation.class.isAssignableFrom((Class<?>) target)) {\n\t\t\t\t\treturn (Class<? extends Annotation>) target;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tthrow new ClassCastException(\"Not an annotation type: \" + target);\n\t\t}\n\t\treturn null;\n\t}\n}\n","sourceCodeStart":175,"sourceCodeEnd":198,"githubUrl":"https://github.com/projectlombok/lombok/blob/6d6a3e9fec0a9555702561fbeb8eac836575116e/src/utils/lombok/core/SpiLoadUtil.java#L175-L198","documentation":"SpiLoadUtil.findAnnotationHelper resolves an annotation class from a service-loader config value, which may be a Class or a Field. If the resolved target is neither null nor a Class assignable to java.lang.annotation.Annotation, it throws this ClassCastException. It means the configured type is not an annotation type as required.","triggerScenarios":"findAnnotationClass -> findAnnotationHelper with a registration whose value is a Class that does not extend Annotation (e.g. a plain class, interface, or enum listed where an annotation is expected) — typical of a typo'd FQN in a service/annotation-map config or a class placed under the wrong registration key.","commonSituations":"Typing a handler class name where the annotation FQN should go; renaming/refactoring an annotation so the config still points at the old non-annotation class; registering the annotation's processor class instead of the annotation itself.","solutions":["Check the configured value at <target>: it must be the fully-qualified name of an @interface (annotation type), not a class or enum.","Fix the FQN in the service/config registration to reference the annotation itself (e.g. lombok.foo.HandlerAnnotation), not its processor.","Verify the referenced type still extends java.lang.annotation.Annotation after refactors; update stale names.","If the target may legitimately be absent, note that findAnnotationHelper returns null (not an exception) when the field value is null — only non-Class, non-Annotation values throw."],"exampleFix":"// before (config value points at a class, not an annotation)\nlombok.launch.AnnotationProcessorHider$AstModificationNotifier  -> ClassCastException\n// after (point at the annotation type)\nlombok.extern.java.Log","handlingStrategy":"validation","validationCode":"Object target = ...; // resolved config value\nif (target instanceof Class<?> c && !java.lang.annotation.Annotation.class.isAssignableFrom(c))\n    throw new IllegalStateException(\"Configured type is not an annotation: \" + c.getName());","typeGuard":"static boolean isAnnotationType(Object o) {\n    return o instanceof Class<?> c && java.lang.annotation.Annotation.class.isAssignableFrom(c);\n}","tryCatchPattern":"try {\n    Class<? extends Annotation> ann = findAnnotationClass(field, loader);\n} catch (ClassCastException e) {\n    if (e.getMessage().startsWith(\"Not an annotation type:\")) {\n        // fix the FQN in the service config to point at the @interface\n    } else throw e;\n}","preventionTips":["Register the annotation type (@interface FQN), not the handler/processor class.","After renaming annotations, grep service/config files for stale names.","Validate with Annotation.class.isAssignableFrom before resolving.","Keep annotation and processor FQNs distinct in config to avoid mixups."],"tags":["spi","annotation","type-mismatch","java"],"backgroundTag":"type-mismatch","analyzedSha":"6d6a3e9fec0a9555702561fbeb8eac836575116e","analyzedAt":"2026-09-07T23:18:01.841Z","contentChangedAt":"2026-09-07T23:18:01.841Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}