quarkusio/quarkus · error · DefinitionException

Multiple disposer methods found for producer '${producer}' d

Error message

Multiple disposer methods found for producer '${producer}' declared on ${declaringBean}:
	- ${disposerMethod}

What it means

CDI allows at most one disposer method per producer. If two or more disposer methods resolve to the same producer (matching the produced type and qualifiers) within the same bean class, ArC throws this DefinitionException listing all offending disposer methods.

Source

Thrown at independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java:1558

                }
                if (hasQualifier) {
                    Type disposedParamType = disposer.getDisposedParameterType();
                    for (Type beanType : beanTypes) {
                        if (beanResolver.matches(disposedParamType, beanType)) {
                            found.add(disposer);
                            break;
                        }
                    }
                }
            }
        }
        if (found.size() > 1) {
            StringBuilder error = new StringBuilder("Multiple disposer methods found for producer '")
                    .append(producer).append("' declared on ").append(declaringBean).append(":\n");
            for (DisposerInfo disposer : found) {
                error.append("\t- ").append(disposer.getDisposerMethod()).append("\n");
            }
            throw new DefinitionException(error.toString());
        }
        return found.isEmpty() ? null : found.get(0);
    }

    // keep it public we need this method in quarkus integration
    public static Set<DotName> initBeanDefiningAnnotations(Collection<BeanDefiningAnnotation> additionalBeanDefiningAnnotations,
            Set<DotName> stereotypes) {
        Set<DotName> beanDefiningAnnotations = new HashSet<>();
        for (BuiltinScope scope : BuiltinScope.values()) {
            beanDefiningAnnotations.add(scope.getInfo().getDotName());
        }
        if (additionalBeanDefiningAnnotations != null) {
            for (BeanDefiningAnnotation additional : additionalBeanDefiningAnnotations) {
                beanDefiningAnnotations.add(additional.getAnnotation());
            }
        }
        beanDefiningAnnotations.addAll(stereotypes);
        return beanDefiningAnnotations;

View on GitHub (pinned to e1c734241f)

Solutions

  1. Delete one of the duplicate disposer methods, consolidating cleanup logic into the remaining one.
  2. If both cleanups are needed, call both operations from a single disposer method.
  3. Rename qualifiers/types so each disposer matches a distinct producer.

Example fix

// before
class Cfg {
  @Produces Conn connect() { ... }
  @Disposes void closeA(Conn c) { c.close(); }
  @Disposes void closeB(Conn c) { c.release(); }
}
// after
class Cfg {
  @Produces Conn connect() { ... }
  @Disposes void close(Conn c) { c.release(); c.close(); }
}
Defensive patterns

Strategy: validation

Validate before calling

// At build time: count disposer methods per bean class
long disposers = Arrays.stream(cls.getDeclaredMethods())
        .filter(m -> Arrays.stream(m.getParameterAnnotations())
                .flatMap(Stream::of).anyMatch(a -> a instanceof Disposes.class)).count();
if (disposers > 1) {
    throw new IllegalStateException("More than one disposer in " + cls);
}

Prevention

When it happens

Trigger: Two @Disposes methods in a bean class both accept parameters assignable to the same producer's type/qualifiers — typically duplicates created by inheritance or copy-paste of a close()/cleanup() method.

Common situations: Copy-pasting a disposer to handle cleanup differently; subclass adding a disposer for an inherited producer; merging branches that each added a disposer for the same producer.

Related errors


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