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

  1. Only unload IDs that a prior successful loadCollection registered
  2. Treat unload-of-unknown as a no-op in teardown paths (catch and continue)
  3. 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

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


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