{"record":{"id":"91674a361fea638e","repo":"musistudio/claude-code-router","slug":"plugin-pluginid-rollback-resource-cleanup-fai","errorCode":null,"errorMessage":"[plugin:${pluginId}] Rollback resource cleanup failed: ${formatError(error)}","messagePattern":"\\[plugin:(.+?)\\] Rollback resource cleanup failed: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/core/src/plugins/service.ts","lineNumber":923,"sourceCode":"    this.gatewayRoutes = snapshot.gatewayRoutes;\n    this.providerAccountConnectors = snapshot.providerAccountConnectors;\n    this.proxyRoutes = snapshot.proxyRoutes;\n    this.resourceOwnerIds = snapshot.resourceOwnerIds;\n    this.stopHooks = snapshot.stopHooks;\n    this.virtualModelProfiles = snapshot.virtualModelProfiles;\n\n    for (const stopHook of newStopHooks) {\n      try {\n        await stopHook.stop({ reason: \"disabled\" });\n      } catch (error) {\n        console.warn(`[plugin:${pluginId}] Rollback stop hook failed: ${formatError(error)}`);\n      }\n    }\n\n    try {\n      await backendService.stopOwner(pluginId);\n    } catch (error) {\n      console.warn(`[plugin:${pluginId}] Rollback resource cleanup failed: ${formatError(error)}`);\n    }\n  }\n}\n\nexport const pluginService = new GatewayPluginService();\n\nfunction pluginPermissionAccess(pluginConfig: Pick<GatewayPluginConfig, \"enabled\" | \"id\" | \"permissions\">): PluginPermissionAccess {\n  const permissions = pluginConfig.permissions\n    ?? knownGatewayPluginDefaultPermissions(pluginConfig.id)\n    ?? (pluginConfig.enabled === true ? undefined : [...GATEWAY_PLUGIN_PERMISSION_IDS]);\n  return {\n    explicit: permissions !== undefined,\n    permissions: new Set(permissions ?? []),\n    pluginId: pluginConfig.id\n  };\n}\n\nfunction pluginPermissionList(access: PluginPermissionAccess): GatewayPluginPermission[] {","sourceCodeStart":905,"sourceCodeEnd":941,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/plugins/service.ts#L905-L941","documentation":"The final step of plugin-load rollback calls backendService.stopOwner(pluginId) to release the plugin's owned resources (SQLite stores, servers). If that call itself throws, this warning is logged and rollback ends; the process stays up but the plugin's backend resources may leak until restart.","triggerScenarios":"Rollback of a failed plugin load where stopOwner throws — e.g. an owned child process or store refuses to stop, or cleanup logic throws outside the per-store try/catch seen in stopOwner.","commonSituations":"Plugin that spawns processes/opens stores and fails startup; repeated config reloads accumulating leaked resources; a backend owner type with buggy teardown.","solutions":["Fix the plugin's original startup failure so rollback is never needed.","Restart the gateway after such a warning to reclaim any leaked resources.","Report/update the backend owner implementation whose stopOwner threw (the message includes the cause).","Avoid config hot-reloads of the broken plugin until fixed."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Restart the gateway after rollback warnings to reclaim leaked resources","Fix failing plugin startup to avoid rollback paths","Avoid hot-reloading broken plugin configs"],"tags":["plugins","rollback","resource-leak","cleanup"],"backgroundTag":"resource-cleanup-failed","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}