{"record":{"id":"8df03bbe9d3147f8","repo":"ruvnet/ruflo","slug":"plugin-initialization-failed-initerrors-join","errorCode":null,"errorMessage":"Plugin initialization failed:\n${initErrors.join('\n')}","messagePattern":"Plugin initialization failed:\n(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"v3/@claude-flow/plugins/src/registry/enhanced-plugin-registry.ts","lineNumber":423,"sourceCode":"    switch (strategy) {\n      case 'sequential':\n        await this.initializeSequential();\n        break;\n      case 'parallel':\n        await this.initializeParallel();\n        break;\n      case 'parallel-safe':\n        await this.initializeParallelSafe();\n        break;\n    }\n\n    // Check for initialization errors (including conflicts)\n    const initErrors = Array.from(this.plugins.values())\n      .filter(e => e.error)\n      .map(e => `${e.plugin.metadata.name}: ${e.error}`);\n\n    if (initErrors.length > 0) {\n      throw new Error(`Plugin initialization failed:\\n${initErrors.join('\\n')}`);\n    }\n\n    this.initialized = true;\n    this.logger.info(`Registry initialized with ${this.plugins.size} plugins (${strategy})`);\n  }\n\n  private async initializeSequential(): Promise<void> {\n    const loadOrder = this.dependencyGraph.getLoadOrder();\n\n    for (const name of loadOrder) {\n      const entry = this.plugins.get(name);\n      if (!entry) continue;\n\n      if (!entry.config.enabled) {\n        this.logger.info(`Plugin ${name} is disabled, skipping initialization`);\n        continue;\n      }\n","sourceCodeStart":405,"sourceCodeEnd":441,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/plugins/src/registry/enhanced-plugin-registry.ts#L405-L441","documentation":"Thrown at the end of EnhancedPluginRegistry.initialize() when any plugin's init recorded an error. Initialization runs by strategy (sequential, parallel, parallel-safe) and captures per-plugin failures into each entry's error field instead of throwing immediately; afterwards initialize() collects every 'pluginName: error' pair and throws this aggregate, so one or more plugin init failures abort the whole registry initialization (initialized stays false).","triggerScenarios":"A plugin's init() rejecting (bad config, missing API key, unreachable service) during initialize(); initialization conflicts recorded as errors (e.g. extension name collisions under the 'error' resolution strategy); a plugin timing out within its init and recording an error; any strategy (sequential/parallel/parallel-safe) since all funnel through the same post-check.","commonSituations":"External-service plugins (DB, LLM) whose init fails from missing env vars/credentials in the deployed environment; order-dependent plugins initializing in parallel and conflicting; one broken third-party plugin blocking the entire app boot; transient network failure during init treated as fatal.","solutions":["Parse each line of the aggregate message to find which plugin(s) failed and why; fix that plugin's init problem (config, credentials, connectivity)","Make the failing plugin's init resilient (retry, defaults, or graceful degradation) so a single plugin cannot abort registry startup","For name-collision errors, change the registry's conflict resolution strategy away from 'error' or rename the conflicting extension","If the plugin is non-essential, unregister it (or register it later) so initialize() can succeed without it"],"exampleFix":"// before\nawait registry.initialize();\n// throws: Plugin initialization failed:\n//   db-plugin: connect ECONNREFUSED localhost:5432\n\n// after - make the plugin's init non-fatal:\nasync init(ctx) {\n  try {\n    await this.client.connect();\n  } catch (err) {\n    ctx.logger.warn('db-plugin degraded:', err.message);\n    this.degraded = true; // init() still resolves\n  }\n}\nawait registry.initialize(); // succeeds, db-plugin degraded","handlingStrategy":"try-catch","validationCode":"// Optional dry run: surface failing init early per-plugin instead of aborting the registry\nfor (const plugin of pluginsToLoad) {\n  try {\n    await plugin.init?.({ logger }); // minimal context\n  } catch (err) {\n    logger.warn(`plugin ${plugin.metadata.name} init will fail: ${(err as Error).message}`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await registry.initialize();\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Plugin initialization failed')) {\n    const failed = err.message.split('\\n').slice(1); // 'name: cause' lines\n    for (const line of failed) logger.error(`init failure: ${line}`);\n    // option: unregister failing plugins and retry initialize() on a fresh registry\n  }\n  throw err;\n}","preventionTips":["Make non-essential plugin init non-fatal: degrade inside init() instead of rejecting","Validate plugin config (env vars, credentials, endpoints) before initialize() runs","Prefer the 'parallel-safe' strategy so one plugin's init failure does not poison others","Surface per-plugin init health in diagnostics after boot"],"tags":["initialization","aggregate-error","plugin-registry","typescript"],"backgroundTag":"plugin-initialization-failure","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}