ruvnet/ruflo · error
Plugin ${name} not found
Error message
Plugin ${name} not found What it means
Thrown by EnhancedPluginRegistry.unregister(name) as its first statement: a plain plugins.get(name) lookup that missed. Nothing else runs before it, so this error means exactly that no plugin with that name is registered on this registry instance (never registered, already unregistered, or name mismatch).
Source
Thrown at v3/@claude-flow/plugins/src/registry/enhanced-plugin-registry.ts:351
// Store entry
const entry: PluginEntry = {
plugin: resolvedPlugin,
config: pluginConfig,
loadTime: new Date(),
};
this.plugins.set(name, entry);
this.eventBus.emit(PLUGIN_EVENTS.LOADED, { plugin: name });
this.logger.info(`Plugin registered: ${name} v${version}`);
}
/**
* Unregister a plugin with dependency checking.
*/
async unregister(name: string, options?: UnregisterOptions): Promise<void> {
const entry = this.plugins.get(name);
if (!entry) {
throw new Error(`Plugin ${name} not found`);
}
// Check dependents
const dependents = this.dependencyGraph.getDependents(name);
if (dependents.length > 0) {
if (options?.cascade) {
// Unload dependents first (in reverse order)
const order = this.dependencyGraph.getRemovalOrder(name);
for (const dep of order) {
if (dep !== name) {
await this.shutdownPlugin(dep);
this.removePluginFromGraph(dep);
}
}
} else if (options?.force) {
this.logger.warn(`Force removing ${name}, breaking: ${dependents.join(', ')}`);
} else {View on GitHub (pinned to fa13ee4ad6)
Solutions
- List registered plugins (registry list API or logs) and use the exact metadata.name
- Make teardown idempotent: only unregister when the plugin is actually present
- Source the name from the plugin object's metadata rather than a duplicated string literal
Example fix
// before
await registry.unregister('logger-plugin'); // registered as 'logger' -> throws
// after
const registered = (await registry.list()).map(p => p.metadata.name);
if (registered.includes('logger')) {
await registry.unregister('logger');
} Defensive patterns
Strategy: validation
Validate before calling
const registered = new Set((await registry.list()).map(p => p.metadata.name));
if (!registered.has(name)) {
logger.debug(`unregister skipped: '${name}' not registered`);
} else {
await registry.unregister(name);
} Try / catch
try {
await registry.unregister(name);
} catch (err) {
if (err instanceof Error && err.message.endsWith('not found')) return; // idempotent teardown
throw err;
} Prevention
- Make teardown idempotent: tolerate 'not found' on unregister
- Take unregister names from the same metadata.name used at registration
- Run teardown once (leaf plugins first) from a single shutdown path
When it happens
Trigger: Calling unregister('my-plugin') when the plugin registered under a different metadata.name; unregistering during shutdown after it was already unregistered (double-teardown); typo or casing differences between the registration name and the teardown call.
Common situations: Cleanup code in tests running against a fresh registry; shutdown handlers racing with a prior unregister; name drift between the plugin package's metadata and hard-coded teardown strings.
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/fe7c820be8d1718f.
Report an issue: GitHub.