quarkusio/quarkus · error · IllegalArgumentException
Annotation does not have @Retention(RUNTIME):
Error message
Annotation does not have @Retention(RUNTIME):
What it means
Arc's AnnotationLiteralProcessor generates annotation literal subclasses at build time. Jandex annotations must be marked runtime-visible (i.e. @Retention(RUNTIME)) for literal generation; otherwise an IllegalArgumentException is thrown naming the offending annotation instance.
Source
Thrown at independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralProcessor.java:88
* if not. Further, it is expected that the annotation type is available (that is,
* {@code annotationClass != null}); an exception is thrown if not. Callers that expect
* they always deal with runtime-retained annotations whose classes are available do not
* have to check (and will get decent errors for free), but callers that can possibly deal
* with class-retained annotations or missing annotation classes must check explicitly.
* <p>
* We call the generated implementation of the annotation type an <em>annotation literal class</em>
* and the instance produced by the generated bytecode an <em>annotation literal instance</em>,
* even though the generated code doesn't use CDI's {@code AnnotationLiteral}.
*
* @param bc will receive the bytecode sequence for instantiating the annotation literal class
* as a sequence of {@link BlockCreator} method calls
* @param annotationClass the annotation type
* @param annotationInstance the annotation instance; must match the {@code annotationClass}
* @return an annotation literal instance result handle
*/
public Expr create(BlockCreator bc, ClassInfo annotationClass, AnnotationInstance annotationInstance) {
if (!annotationInstance.runtimeVisible()) {
throw new IllegalArgumentException("Annotation does not have @Retention(RUNTIME): " + annotationInstance);
}
if (annotationClass == null) {
throw new IllegalArgumentException("Annotation class not available: " + annotationInstance);
}
AnnotationLiteralClassInfo literal = cache.getValue(new CacheKey(annotationClass));
ClassDesc generatedClass = ClassDesc.of(literal.generatedClassName);
if (literal.annotationMembers().isEmpty()) {
return bc.getStaticField(FieldDesc.of(generatedClass, "INSTANCE", generatedClass));
}
Expr[] ctorArgs = new Expr[literal.annotationMembers().size()];
int argIndex = 0;
for (MethodInfo annotationMember : literal.annotationMembers()) {
AnnotationValue value = annotationInstance.value(annotationMember.name());
if (value == null) {View on GitHub (pinned to e1c734241f)
Solutions
- Declare the annotation with @Retention(RetentionPolicy.RUNTIME)
- Remove the non-runtime annotation from CDI-managed code
- Check that the Jandex index reflects the compiled annotation retention
Example fix
// before
@Target(TYPE) @Retention(RetentionPolicy.CLASS)
public @interface MyMarker {}
// after
@Target(TYPE) @Retention(RetentionPolicy.RUNTIME)
public @interface MyMarker {} Defensive patterns
Strategy: validation
Validate before calling
Retention r = MyAnno.class.getAnnotation(Retention.class); if (r == null || r.value() != RetentionPolicy.RUNTIME) throw new IllegalArgumentException("needs RUNTIME"); Prevention
- Use @Retention(RUNTIME) on CDI annotations
When it happens
Trigger: Arc.create(...) processing an annotation instance whose runtimeVisible() flag is false — typically a source/class-retention annotation — passed to AnnotationLiteralProcessor.create.
Common situations: Using an annotation declared with @Retention(SOURCE) or @Retention(CLASS) in CDI injection points; indexing code where retention metadata differs from expectations; custom annotations missing @Retention(RUNTIME).
Related errors
- Array component kind is
- TransformedAnnotationsBuildItem#queryForMethodParam needs to
- Annotation class not available:
- Value is not set for %s.%s(). Most probably an older version
- Class of nested annotation missing
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/93bc551056d0c6ed.
Report an issue: GitHub.