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 } : t

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Rename one plugin's extension identifier so contributions are unique
  2. Configure a non-error conflict strategy for the category (rename/namespace/prefix/suffix) so the registry auto-disambiguates identifiers like '{plugin}-{name}'
  3. 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

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


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/4bda853b5e757f71. Report an issue: GitHub.