alibaba/COLA · error · ExtensionException
EXTENSION_DEFINE_DUPLICATE
EXTENSION_DEFINE_DUPLICATE
Error message
Duplicate registration is not allowed for :${extensionCoordinate} What it means
ExtensionRegister.doRegistration puts each @Extension implementation into the extension repository keyed by an ExtensionCoordinate (extension point interface + BizScenario identity). If put() returns a previous value, an extension is already registered for that exact coordinate, and ExtensionException with code EXTENSION_DEFINE_DUPLICATE is thrown to protect against silently overwriting behavior. One business coordinate must map to exactly one implementation.
Source
Thrown at cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/register/ExtensionRegister.java:57
@Resource
private ExtensionRepository extensionRepository;
public final static String EXTENSION_EXTPT_NAMING = "ExtPt";
public void doRegistration(ExtensionPointI extensionObject) {
Class<?> extensionClz = extensionObject.getClass();
if (AopUtils.isAopProxy(extensionObject)) {
extensionClz = AopUtils.getTargetClass(extensionObject);
}
Extension extensionAnn = AnnotatedElementUtils.findMergedAnnotation(extensionClz, Extension.class);
BizScenario bizScenario = BizScenario.valueOf(extensionAnn.bizId(), extensionAnn.useCase(), extensionAnn.scenario());
ExtensionCoordinate extensionCoordinate = new ExtensionCoordinate(calculateExtensionPoint(extensionClz), bizScenario.getUniqueIdentity());
ExtensionPointI preVal = extensionRepository.getExtensionRepo().put(extensionCoordinate, extensionObject);
if (preVal != null) {
String errMessage = "Duplicate registration is not allowed for :" + extensionCoordinate;
throw new ExtensionException(EXTENSION_DEFINE_DUPLICATE, errMessage);
}
}
public void doRegistrationExtensions(ExtensionPointI extensionObject){
Class<?> extensionClz = extensionObject.getClass();
if (AopUtils.isAopProxy(extensionObject)) {
extensionClz = ClassUtils.getUserClass(extensionObject);
}
Extensions extensionsAnnotation = AnnotationUtils.findAnnotation(extensionClz, Extensions.class);
//Support multiple extensions registration
String[] bizIds = extensionsAnnotation.bizId();
String[] useCases = extensionsAnnotation.useCase();
String[] scenarios = extensionsAnnotation.scenario();
for (String bizId : bizIds) {
for (String useCase : useCases) {
for (String scenario : scenarios) {View on GitHub (pinned to 352e1a8675)
Solutions
- Find the two @Extension classes claiming the same coordinate (the message names the ExtensionCoordinate) and change one's bizId/useCase/scenario to a distinct value.
- Remove the redundant bean or narrow its component-scan/package so it registers once.
- If behavior should be replaced, delete the old extension implementation rather than adding a new one with identical identity.
- Use distinct scenarios via doRegistrationExtensions (@Extension with a scenario list) when one class legitimately serves multiple scenarios — but ensure no overlap with other classes.
Example fix
// before (two classes both declare this) @Extension(bizId = "trade", useCase = "refund", scenario = "normal") // after — make the second implementation's identity unique @Extension(bizId = "trade", useCase = "refund", scenario = "vip")
Defensive patterns
Strategy: validation
Validate before calling
// startup self-check
Set<String> seen = new HashSet<>();
for (Object ext : extensions) {
Extension a = AnnotatedElementUtils.findMergedAnnotation(ext.getClass(), Extension.class);
if (!seen.add(a.bizId() + "|" + a.useCase() + "|" + a.scenario())) { throw new IllegalStateException("Duplicate @Extension identity"); }
} Try / catch
try { applicationContext.register(...); context.refresh(); } catch (ExtensionException e) { if ("EXTENSION_DEFINE_DUPLICATE".equals(e.getErrCode())) { log.error(e.getMessage()); /* fail startup with actionable message */ } throw e; } Prevention
- Keep @Extension identities in a registry of constants to avoid copy-paste collisions
- One team owns each bizId.useCase namespace
- Add a unit test scanning @Extension annotations for uniqueness
- Avoid registering the same class through multiple bean-definition paths
When it happens
Trigger: Spring startup/registration of two beans annotated @Extension with the same bizId/useCase/scenario for the same extension point interface — e.g. copy-pasted extension classes, or the same class registered twice (multiple bean definitions, double component scan).
Common situations: Copy-pasting an extension class without changing @Extension(bizId/useCase/scenario); two modules in a multi-module project both defining an extension for the same scenario; duplicate @Component scanning of the same package.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- EXTENSION_NOT_FOUND
- Component ${targetClz} can not be found in Spring Container
- BizScenario can not be null for extension
- Component ${targetClz} can not be found in Spring Container
- B_CUSTOMER_companyNameConflict
AI-assisted analysis of alibaba/COLA@352e1a8675 (2026-09-08).
Data as JSON: /api/errors/2105ce2d27c4cfd9.
Report an issue: GitHub.