{"record":{"id":"2d9e73d26443fbd6","repo":"ruvnet/ruflo","slug":"collection-collection-id-already-loaded","errorCode":null,"errorMessage":"Collection ${collection.id} already loaded","messagePattern":"Collection (.+?) already loaded","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/plugins/src/collections/collection-manager.ts","lineNumber":125,"sourceCode":"  private pluginSettings = new Map<string, Record<string, unknown>>();\n  private registry: PluginRegistry;\n  private autoInitialize: boolean;\n\n  constructor(config: CollectionManagerConfig) {\n    this.registry = config.registry;\n    this.autoInitialize = config.autoInitialize ?? true;\n  }\n\n  // =========================================================================\n  // Collection Management\n  // =========================================================================\n\n  /**\n   * Load a plugin collection.\n   */\n  async loadCollection(collection: PluginCollection): Promise<void> {\n    if (this.collections.has(collection.id)) {\n      throw new Error(`Collection ${collection.id} already loaded`);\n    }\n\n    // Resolve all plugins upfront to cache names\n    const resolved: ResolvedEntry[] = [];\n    for (const entry of collection.plugins) {\n      const plugin = await this.resolvePlugin(entry.plugin);\n      resolved.push({\n        entry,\n        pluginName: plugin.metadata.name,\n        plugin,\n      });\n    }\n\n    this.collections.set(collection.id, collection);\n    this.resolvedEntries.set(collection.id, resolved);\n    this.enabledOverrides.set(collection.id, new Set());\n    this.disabledOverrides.set(collection.id, new Set());\n","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/plugins/src/collections/collection-manager.ts#L107-L143","documentation":"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.","triggerScenarios":"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.","commonSituations":"Test suites sharing manager state; watch-mode or reload loops; startup code that loads a collection while a plugin also loads it explicitly.","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"],"exampleFix":"// before\nawait manager.loadCollection(collection); // second call throws 'already loaded'\n\n// after\nif (loadedIds.has(collection.id)) {\n  await manager.unloadCollection(collection.id);\n  loadedIds.delete(collection.id);\n}\nawait manager.loadCollection(collection);\nloadedIds.add(collection.id);","handlingStrategy":"validation","validationCode":"const loadedIds = new Set<string>();\nasync function loadOnce(manager: CollectionManager, collection: PluginCollection) {\n  if (loadedIds.has(collection.id)) return; // or unload first to reload\n  await manager.loadCollection(collection);\n  loadedIds.add(collection.id);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await manager.loadCollection(collection);\n} catch (e) {\n  if (e instanceof Error && e.message.endsWith('already loaded')) {\n    await manager.unloadCollection(collection.id);\n    await manager.loadCollection(collection); // reload\n  } else throw e;\n}","preventionTips":["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"],"tags":["plugins","collection-manager","duplicate","lifecycle"],"backgroundTag":"duplicate-entity","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}