ruvnet/ruflo · error · Error
Cannot disable ${pluginName}: other plugins may depend on it
Error message
Cannot disable ${pluginName}: other plugins may depend on it What it means
disablePlugin flips the enabled/disabled override sets first, then calls registry.unregister(pluginName) inside try/catch; any registry failure — in practice, other registered plugins depend on this one — is swallowed and rethrown as this generic message. Note two consequences: the original cause is hidden, and the disabled override has already been recorded even though the plugin remains registered.
Source
Thrown at v3/@claude-flow/plugins/src/collections/collection-manager.ts:234
* Disable a plugin from a collection.
*/
async disablePlugin(collectionId: string, pluginName: string): Promise<void> {
const resolved = this.findResolvedEntry(collectionId, pluginName);
if (!resolved) {
throw new Error(`Plugin ${pluginName} not found in collection ${collectionId}`);
}
// Remove from enabled, add to disabled
this.enabledOverrides.get(collectionId)?.delete(pluginName);
this.disabledOverrides.get(collectionId)?.add(pluginName);
// Unregister if registered
if (this.registry.getPlugin(pluginName)) {
try {
await this.registry.unregister(pluginName);
} catch {
// May fail if other plugins depend on it
throw new Error(`Cannot disable ${pluginName}: other plugins may depend on it`);
}
}
}
/**
* Check if a plugin is enabled.
*/
isEnabled(collectionId: string, pluginName: string): boolean {
const resolved = this.findResolvedEntry(collectionId, pluginName);
if (!resolved) return false;
return this.isPluginEnabledSync(collectionId, pluginName, resolved.entry.defaultEnabled);
}
/**
* Toggle a plugin's enabled state.
*/
async togglePlugin(collectionId: string, pluginName: string): Promise<boolean> {View on GitHub (pinned to fa13ee4ad6)
Solutions
- Identify plugins that depend on it (registry dependency data or collection manifests) and disable them first
- For teardown, disable plugins in reverse dependency order
- If the cause is unclear, call registry.unregister(pluginName) directly to surface the real error the manager swallowed
Example fix
// before
await manager.disablePlugin('analytics', 'auth'); // dependents still registered -> throws
// after
for (const dep of dependentsOf('auth')) {
await manager.disablePlugin('analytics', dep);
}
await manager.disablePlugin('analytics', 'auth'); Defensive patterns
Strategy: try-catch
Validate before calling
// if the registry exposes dependency data, pre-check dependents:
const dependents = registry
.listPlugins()
.filter((p) => (p.dependencies ?? []).includes(pluginName))
.map((p) => p.name);
if (dependents.length > 0) {
throw new Error(`disable dependents first: ${dependents.join(', ')}`);
}
await manager.disablePlugin(collectionId, pluginName); Try / catch
try {
await manager.disablePlugin(collectionId, pluginName);
} catch (e) {
if (e instanceof Error && e.message.startsWith('Cannot disable') && e.message.includes('depend on it')) {
// discover dependents via the registry, disable them first, then retry;
// for the true root cause call registry.unregister(pluginName) directly,
// since the manager swallows the original error
} else throw e;
} Prevention
- Disable plugins in reverse dependency (topological) order
- Document each plugin's dependents next to its enable/disable config
- When diagnosing, bypass the manager and call the registry directly to see the real error
When it happens
Trigger: Disabling a plugin that other registered plugins list as a dependency; any registry.unregister failure (the underlying error is masked, hence the hedged 'may depend on it').
Common situations: Disabling shared infrastructure plugins (auth, telemetry) that a collection's other plugins depend on; teardown ordering issues in plugin dependency graphs; registry state problems producing unregister errors.
Related errors
- Collection ${collection.id} already loaded
- Collection ${collectionId} not found
- Plugin ${pluginName} not found in collection ${collectionId}
- DUPLICATE_PLUGIN
- Failed to register MCP tools: ${registration.failed.join(',
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/75136694e6dbd212.
Report an issue: GitHub.