quarkusio/quarkus · error · DeploymentException
Method '' of class '' contains both @Blocking and @NonBlocki
Error message
Method '' of class '' contains both @Blocking and @NonBlocking annotations.
What it means
A method cannot be annotated with both @Blocking and @NonBlocking — the desired execution model would be ambiguous. EndpointIndexer detects the conflict and throws this DeploymentException when both annotations target the same method (same annotation target kind METHOD).
Source
Thrown at independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java:922
if (blockingAnnotation != null) {
return false;
} else {
return defaultValue == BlockingDefault.RUN_ON_VIRTUAL_THREAD;
}
}
}
private boolean isBlocking(MethodInfo info, BlockingDefault defaultValue) {
Map.Entry<AnnotationTarget, AnnotationInstance> blockingAnnotation = getInheritableAnnotation(info, BLOCKING);
Map.Entry<AnnotationTarget, AnnotationInstance> runOnVirtualThreadAnnotation = getInheritableAnnotation(info,
RUN_ON_VIRTUAL_THREAD);
Map.Entry<AnnotationTarget, AnnotationInstance> nonBlockingAnnotation = getInheritableAnnotation(info,
NON_BLOCKING);
if ((blockingAnnotation != null) && (nonBlockingAnnotation != null)) {
if (blockingAnnotation.getKey().kind() == nonBlockingAnnotation.getKey().kind()) {
if (blockingAnnotation.getKey().kind() == AnnotationTarget.Kind.METHOD) {
throw new DeploymentException(
"Method '" + info.name() + "' of class '" + info.declaringClass().name()
+ "' contains both @Blocking and @NonBlocking annotations.");
} else {
throw new DeploymentException("Class '" + info.declaringClass().name()
+ "' contains both @Blocking and @NonBlocking annotations.");
}
}
if (blockingAnnotation.getKey().kind() == AnnotationTarget.Kind.METHOD) {
// the most specific annotation was the @Blocking annotation on the method
return true;
} else {
// the most specific annotation was the @NonBlocking annotation on the method
return false;
}
} else if ((blockingAnnotation != null)) {
return true;
} else if ((nonBlockingAnnotation != null)) {
return false;View on GitHub (pinned to e1c734241f)
Solutions
- Remove the @NonBlocking annotation from the method, keeping @Blocking
- Or remove @Blocking and keep @NonBlocking if the method is reactive
- Decide one execution model per method based on whether it performs blocking I/O
Example fix
// before
@Blocking
@NonBlocking
public String get() { ... }
// after
@Blocking
public String get() { ... } Defensive patterns
Strategy: validation
Validate before calling
Method m = MyResource.class.getMethod("get");
if (m.isAnnotationPresent(Blocking.class) && m.isAnnotationPresent(NonBlocking.class)) {
throw new IllegalStateException("Both @Blocking and @NonBlocking on " + m);
} Prevention
- Choose one execution model per method: blocking I/O => @Blocking, reactive => @NonBlocking
- Watch for copy-paste and merge conflicts around threading annotations
- Check superclass/interface annotations that may conflict via inheritance
- Add CI annotation-scanning tests for resource classes
When it happens
Trigger: Deploying a resource method that (after annotation inheritance/inheritable lookup) resolves to having both a @Blocking and a @NonBlocking annotation directly on the method.
Common situations: Copy-pasting annotations from another endpoint; a merge conflict leaving both annotations in place; IDE auto-import adding @NonBlocking next to an existing @Blocking while experimenting with threading behavior.
Related errors
- Class '' contains both @Blocking and @NonBlocking annotation
- Endpoints that produce a Multipart result can only be used o
- Method '' of class '' is considered a non blocking method. @
- Parameter: ${i} of the constructor of class '${resourceDotNa
- Unable to load handled exception type ${i.getProvidedType()}
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/30ddd7a5769ec689.
Report an issue: GitHub.