ruvnet/ruflo · error
${category}: ${identifier} conflict between ${existing} and
Error message
${category}: ${identifier} conflict between ${existing} and ${pluginName} What it means
Thrown by EnhancedPluginRegistry's extension-conflict resolution when two plugins contribute an extension with the same identifier (agentTypes, taskTypes, etc.) and the configured resolution strategy for that category is 'error'. The resolver switch handles rename/namespace/prefix/suffix strategies by rewriting the incoming identifier; 'error' (the default) refuses and names both the existing owner and the challenger in the message.
Source
Thrown at v3/@claude-flow/plugins/src/registry/enhanced-plugin-registry.ts:760
const existingNs = template
.replace('{plugin}', existing)
.replace('{name}', identifier);
if (!owners.has(existingNs)) {
this.renameInCache(category, identifier, existingNs);
owners.delete(identifier);
owners.set(existingNs, existing);
}
const newName = template
.replace('{plugin}', pluginName)
.replace('{name}', identifier);
owners.set(newName, pluginName);
return { ...item, name: newName, type: newName } as T;
}
case 'error':
default:
throw new Error(`${category}: ${identifier} conflict between ${existing} and ${pluginName}`);
}
}
private renameInCache(category: string, oldName: string, newName: string): void {
switch (category) {
case 'agentTypes':
this.agentTypesCache = this.agentTypesCache.map(t =>
t.type === oldName ? { ...t, type: newName } : t
);
break;
case 'taskTypes':
this.taskTypesCache = this.taskTypesCache.map(t =>
t.type === oldName ? { ...t, type: newName } : t
);
break;
case 'mcpTools':
this.mcpToolsCache = this.mcpToolsCache.map(t =>
t.name === oldName ? { ...t, name: newName } : tView on GitHub (pinned to fa13ee4ad6)
Solutions
- Rename one plugin's extension identifier so contributions are unique
- Configure a non-error conflict strategy for the category (rename/namespace/prefix/suffix) so the registry auto-disambiguates identifiers like '{plugin}-{name}'
- Unregister the plugin you do not actually need if the duplicate is accidental
Example fix
// before
const registry = new EnhancedPluginRegistry({
coreVersion: '3.0.0',
// conflictResolution unset -> 'error' strategy
});
// both plugins declare agentType 'researcher' -> conflict throws
// after
const registry = new EnhancedPluginRegistry({
coreVersion: '3.0.0',
conflictResolution: {
agentTypes: { strategy: 'prefix' },
taskTypes: { strategy: 'namespace' },
},
}); Defensive patterns
Strategy: validation
Validate before calling
// Pre-scan contributed extensions for collisions before initialize()
const seen = new Map<string, string>(); // identifier -> plugin name
for (const [pluginName, ids] of collectDeclaredExtensions(registeredPlugins)) {
for (const id of ids) {
if (seen.has(id)) {
throw new Error(`${id} declared by both ${seen.get(id)} and ${pluginName}`);
}
seen.set(id, pluginName);
}
} Try / catch
try {
await registry.initialize();
} catch (err) {
if (err instanceof Error && /conflict between/.test(err.message)) {
// reconfigure the strategy to auto-disambiguate, then retry once
registryConfig.conflictResolution = { default: { strategy: 'prefix' } };
return initializeWithFreshRegistry();
}
throw err;
} Prevention
- Namespace your plugin's extension identifiers (e.g. 'acme-researcher') by convention
- Configure conflictResolution strategies (prefix/namespace/rename) instead of the default 'error' when loading third-party packs
- Add a startup duplicate-extension scan so collisions surface with both owners named
When it happens
Trigger: Two registered plugins both declaring an agentType or taskType with the same identifier string while the registry config's conflictResolution for that category is 'error' or unset; registering a plugin whose extension names collide with an existing plugin's; plugin upgrades introducing an extension name another plugin already claims.
Common situations: Two teams' plugins independently shipping a 'researcher' agent type; a fork or customization re-declaring a stock extension identifier; enabling a third-party plugin pack whose identifiers clash with existing ones.
Related errors
- Invalid plugin: does not implement IPlugin interface
- Plugin ${name} already registered
- Maximum plugin limit (${this.config.maxPlugins}) reached
- Plugin ${name} requires core version >= ${resolvedPlugin.met
- Plugin ${name} requires core version <= ${resolvedPlugin.met
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/4bda853b5e757f71.
Report an issue: GitHub.