quarkusio/quarkus · error · IllegalStateException

%s: The class contains a method annotated with @LRA and no m

Error message

%s: The class contains a method annotated with @LRA and no method annotated with @Compensate or @AfterLRA was found.

What it means

Narayana LRA (Long Running Actions) requires that any class participating in an LRA transaction — i.e. containing a method annotated with @LRA — also declares a compensation hook: a method annotated with @Compensate or @AfterLRA. During deployment, NarayanaLRAProcessor.isLRAParticipant scans the class hierarchy for these annotations and throws IllegalStateException at build time if a compensation method is missing, because the participant could never complete or compensate the LRA.

Source

Thrown at extensions/narayana-lra/deployment/src/main/java/io/quarkus/narayana/lra/deployment/NarayanaLRAProcessor.java:102

            int modifiers = classInfo.flags();

            if (Modifier.isInterface(modifiers) || Modifier.isAbstract(modifiers) || !isLRAParticipant(index, classInfo)) {
                continue;
            }

            classNames.add(classInfo.toString());
        }

        recorder.setParticipantTypes(classNames);
    }

    private boolean isLRAParticipant(IndexView index, ClassInfo classInfo) {
        Map<DotName, List<AnnotationInstance>> annotations = getAllAnnotationsFromClassInfoHierarchy(classInfo.name(), index);

        if (!annotations.containsKey(DotNames.LRA)) {
            return false;
        } else if (!annotations.containsKey(DotNames.COMPENSATE) && !annotations.containsKey(DotNames.AFTER_LRA)) {
            throw new IllegalStateException(String.format("%s: %s",
                    classInfo.name(),
                    "The class contains a method annotated with @LRA and no method annotated with @Compensate or @AfterLRA was found."));
        } else {
            return true;
        }
    }

    private Map<DotName, List<AnnotationInstance>> getAllAnnotationsFromClassInfoHierarchy(DotName name,
            IndexView index) {
        Map<DotName, List<AnnotationInstance>> annotations = new HashMap<>();

        if (name == null || name.equals(DotNames.OBJECT)) {
            return annotations;
        }

        ClassInfo classInfo = index.getClassByName(name);

        if (classInfo != null) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add a method annotated with @Compensate to the class (or a superclass) that undoes the work done by the @LRA method.
  2. Alternatively annotate a method with @AfterLRA to receive the LRA completion callback if compensation is not required.
  3. If the class should not be a participant at all, remove the @LRA annotation from its methods.
  4. Ensure the compensating method is on the same class hierarchy as the @LRA method — annotations on unrelated classes are not picked up.

Example fix

// before
public class BookingResource {
    @LRA(value = Type.REQUIRED)
    @Path("/book")
    public Response book() { ... }
}
// after
public class BookingResource {
    @LRA(value = Type.REQUIRED)
    @Path("/book")
    public Response book() { ... }

    @Compensate
    public Response compensate() { ... /* undo booking */ }
}
Defensive patterns

Strategy: validation

Validate before calling

boolean hasLRA = methods.stream().anyMatch(m -> m.isAnnotationPresent(LRA.class));
boolean hasCompensation = methods.stream().anyMatch(m ->
    m.isAnnotationPresent(Compensate.class) || m.isAnnotationPresent(AfterLRA.class));
if (hasLRA && !hasCompensation) {
    throw new IllegalStateException("@LRA class must declare a @Compensate or @AfterLRA method: " + cls.getName());
}

Prevention

When it happens

Trigger: A class with a method annotated with @LRA (in the class or inherited from its hierarchy) has no method annotated with @Compensate and no method annotated with @AfterLRA anywhere in that hierarchy; detected during Quarkus augmentation when createLRAParticipantRegistry indexes LRA participant classes.

Common situations: Writing a first LRA resource and forgetting the compensating method; migrating code from an annotation-based LRA framework with different compensation conventions; refactoring that removes or renames the @Compensate/@AfterLRA method while leaving the @LRA method in place; copy-pasting an example with only the @LRA method.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/420c305cc508db25. Report an issue: GitHub.