ruvnet/ruflo · error · Error
Collection ${collectionId} not found
Error message
Collection ${collectionId} not found What it means
unloadCollection looks the collection up in resolvedEntries; a miss means the manager never successfully loaded that collection (never attempted, failed during plugin resolution, or already unloaded) and the unload is rejected.
Source
Thrown at v3/@claude-flow/plugins/src/collections/collection-manager.ts:158
this.resolvedEntries.set(collection.id, resolved);
this.enabledOverrides.set(collection.id, new Set());
this.disabledOverrides.set(collection.id, new Set());
// Register enabled plugins
for (const { entry, pluginName, plugin } of resolved) {
if (this.isPluginEnabledSync(collection.id, pluginName, entry.defaultEnabled)) {
await this.registerResolvedPlugin(plugin, entry);
}
}
}
/**
* Unload a plugin collection.
*/
async unloadCollection(collectionId: string): Promise<void> {
const resolved = this.resolvedEntries.get(collectionId);
if (!resolved) {
throw new Error(`Collection ${collectionId} not found`);
}
// Unregister all plugins from this collection
for (const { pluginName } of resolved) {
if (this.registry.getPlugin(pluginName)) {
try {
await this.registry.unregister(pluginName);
} catch {
// Ignore errors during unload
}
}
}
this.collections.delete(collectionId);
this.resolvedEntries.delete(collectionId);
this.enabledOverrides.delete(collectionId);
this.disabledOverrides.delete(collectionId);
}View on GitHub (pinned to fa13ee4ad6)
Solutions
- Only unload IDs that a prior successful loadCollection registered
- Treat unload-of-unknown as a no-op in teardown paths (catch and continue)
- After a failed load, skip the corresponding unload
Example fix
// before
await manager.unloadCollection('analytics'); // never loaded -> throws
// after
const loaded = new Set<string>();
try {
await manager.loadCollection(col);
loaded.add('analytics');
} catch { /* load failed: nothing to unload */ }
if (loaded.has('analytics')) await manager.unloadCollection('analytics'); Defensive patterns
Strategy: validation
Validate before calling
const loaded = new Set<string>();
try {
await manager.loadCollection(col);
loaded.add(col.id);
} catch {
// load failed: there is nothing to unload
}
// teardown:
for (const id of loaded) await manager.unloadCollection(id); Try / catch
try {
await manager.unloadCollection(id);
} catch (e) {
if (e instanceof Error && e.message.endsWith('not found')) return; // already clean
throw e;
} Prevention
- Record IDs from successful loads and drive teardown from that record
- Make teardown tolerant of already-unloaded state
- Skip the unload when the matching load threw
When it happens
Trigger: Unloading a never-loaded collection ID; unloading the same collection twice; unloading after a loadCollection that threw during plugin resolution so resolvedEntries was never populated.
Common situations: Cleanup or teardown code that assumes collections exist; double teardown in test hooks; failed loads leaving no entry to unload.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Collection ${collection.id} already loaded
- Plugin ${pluginName} not found in collection ${collectionId}
- Daemon '${name}' not found
- Cannot disable ${pluginName}: other plugins may depend on it
- Can only resume paused agent
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/368555cf85b1d745.
Report an issue: GitHub.