{"record":{"id":"8b644584db561847","repo":"apache/dubbo","slug":"expected-single-matching-bean-but-found-size-ca","errorCode":null,"errorMessage":"expected single matching bean but found ${size} candidates for type [${type}]: ${candidateBeanNames}","messagePattern":"expected single matching bean but found (.+?) candidates for type \\[(.+?)\\]: (.+?)","errorType":"exception","errorClass":"ScopeBeanException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java","lineNumber":348,"sourceCode":"                    } else {\n                        if (candidates == null) {\n                            candidates = new ArrayList<>();\n                            candidates.add(firstCandidate);\n                        }\n                        candidates.add(beanInfo);\n                    }\n                }\n            }\n        }\n\n        // if bean name not matched and only single candidate\n        if (candidates != null) {\n            if (candidates.size() == 1) {\n                return (T) candidates.get(0).instance;\n            } else if (candidates.size() > 1) {\n                List<String> candidateBeanNames =\n                        candidates.stream().map(beanInfo -> beanInfo.name).collect(Collectors.toList());\n                throw new ScopeBeanException(\"expected single matching bean but found \" + candidates.size()\n                        + \" candidates for type [\" + type.getName() + \"]: \" + candidateBeanNames);\n            }\n        } else if (firstCandidate != null) {\n            return (T) firstCandidate.instance;\n        }\n        return null;\n    }\n\n    public void destroy() {\n        if (destroyed.compareAndSet(false, true)) {\n            for (BeanInfo beanInfo : registeredBeanInfos) {\n                if (beanInfo.instance instanceof Disposable) {\n                    try {\n                        Disposable beanInstance = (Disposable) beanInfo.instance;\n                        beanInstance.destroy();\n                    } catch (Throwable e) {\n                        LOGGER.error(\n                                CONFIG_FAILED_DESTROY_INVOKER,","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java#L330-L366","documentation":"Thrown by ScopeBeanFactory.getBeanInternal when resolving by type only (or with a name that does not exactly match) and more than one registered bean is assignable to the requested type. Dubbo cannot guess which instance to return, so it lists the candidate bean names and aborts. This mirrors Spring's NoUniqueBeanDefinitionException.","triggerScenarios":"Calling getBean(type) or getBean(name, type) where name does not equal any registered bean's name, and two or more beans assignable to type exist. Common when multiple implementations of an interface/SPI are registered in the same scope.","commonSituations":"Multiple @DubboService implementations of the same interface; two beans of compatible types registered by different modules sharing a ScopeBeanFactory; custom extensions that register duplicate-type beans; requesting an interface bean without a qualifier.","solutions":["Request the bean by the exact name of one of the candidates listed in the message.","Make the bean name match when registering, so getBean(name, type) resolves uniquely.","Reduce to a single bean of that type in the scope, or mark one as primary/removable for your use case.","If you need all instances, use an injection point for a List<T> / iterate registered beans instead of getBean."],"exampleFix":"// before\nfactory.registerBean(\"a\", MyImpl.class);\nfactory.registerBean(\"b\", MyImpl.class);\nMyApi bean = factory.getBean(MyApi.class);  // ambiguous -> error\n// after\nMyApi bean = factory.getBean(\"a\", MyApi.class);  // exact name match","handlingStrategy":"validation","validationCode":"// Count assignable candidates before resolving by type\n<T> long candidateCount(ScopeBeanFactory f, Class<T> type) {\n    // public getBean throws on ambiguity; instead detect by attempting exact names\n    long n = 0;\n    for (String name : knownNames) {\n        if (f.getBean(name, type) != null) n++;\n    }\n    return n;\n}","typeGuard":null,"tryCatchPattern":"try {\n    T bean = factory.getBean(type);\n} catch (ScopeBeanException e) {\n    if (e.getMessage().startsWith(\"expected single matching bean\")) {\n        // parse candidate names from the message and pick one explicitly:\n        // bean = factory.getBean(candidateName, type);\n    } else throw e;\n}","preventionTips":["Resolve beans by exact name when multiple implementations of a type exist.","Keep one primary bean per type within a scope, or use qualifiers/names consistently.","If you need all instances of a type, iterate registered beans instead of getBean(type).","When registering multiple same-type beans, document and use their names."],"tags":["bean-factory","ambiguous-bean","configuration","dubbo-common"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}