ruvnet/ruflo · error · Error
Collection ${collection.id} already loaded
Error message
Collection ${collection.id} already loaded What it means
CollectionManager.loadCollection registers a collection by ID and refuses a second load of the same ID to prevent duplicate plugin registration. The check is against the collections map, so a collection must be unloaded before it can be loaded again in the same manager instance.
Source
Thrown at v3/@claude-flow/plugins/src/collections/collection-manager.ts:125
private pluginSettings = new Map<string, Record<string, unknown>>();
private registry: PluginRegistry;
private autoInitialize: boolean;
constructor(config: CollectionManagerConfig) {
this.registry = config.registry;
this.autoInitialize = config.autoInitialize ?? true;
}
// =========================================================================
// Collection Management
// =========================================================================
/**
* Load a plugin collection.
*/
async loadCollection(collection: PluginCollection): Promise<void> {
if (this.collections.has(collection.id)) {
throw new Error(`Collection ${collection.id} already loaded`);
}
// Resolve all plugins upfront to cache names
const resolved: ResolvedEntry[] = [];
for (const entry of collection.plugins) {
const plugin = await this.resolvePlugin(entry.plugin);
resolved.push({
entry,
pluginName: plugin.metadata.name,
plugin,
});
}
this.collections.set(collection.id, collection);
this.resolvedEntries.set(collection.id, resolved);
this.enabledOverrides.set(collection.id, new Set());
this.disabledOverrides.set(collection.id, new Set());
View on GitHub (pinned to fa13ee4ad6)
Solutions
- Call unloadCollection(id) and let it finish before loading the same ID again
- Track loaded collections and skip redundant loads
- Use a fresh CollectionManager per test or session instead of a shared singleton
Example fix
// before
await manager.loadCollection(collection); // second call throws 'already loaded'
// after
if (loadedIds.has(collection.id)) {
await manager.unloadCollection(collection.id);
loadedIds.delete(collection.id);
}
await manager.loadCollection(collection);
loadedIds.add(collection.id); Defensive patterns
Strategy: validation
Validate before calling
const loadedIds = new Set<string>();
async function loadOnce(manager: CollectionManager, collection: PluginCollection) {
if (loadedIds.has(collection.id)) return; // or unload first to reload
await manager.loadCollection(collection);
loadedIds.add(collection.id);
} Try / catch
try {
await manager.loadCollection(collection);
} catch (e) {
if (e instanceof Error && e.message.endsWith('already loaded')) {
await manager.unloadCollection(collection.id);
await manager.loadCollection(collection); // reload
} else throw e;
} Prevention
- Wrap loads in an idempotent load-once helper
- Always pair load and unload symmetrically in reload flows
- Reset or recreate the manager between test cases
When it happens
Trigger: Calling loadCollection twice with the same collection.id; hot-reload flows that load a new version before unloading the old one; reusing a single CollectionManager across tests without unloading.
Common situations: Test suites sharing manager state; watch-mode or reload loops; startup code that loads a collection while a plugin also loads it explicitly.
Related errors
- Collection ${collectionId} not found
- Plugin ${pluginName} not found in collection ${collectionId}
- Cannot disable ${pluginName}: other plugins may depend on it
- DUPLICATE_PLUGIN
- Can only resume paused agent
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/2d9e73d26443fbd6.
Report an issue: GitHub.