{"record":{"id":"3eb4a1e5fcc3fe36","repo":"paperclipai/paperclip","slug":"plugin-not-found-after-status-update-pluginid","errorCode":null,"errorMessage":"Plugin not found after status update: ${pluginId}","messagePattern":"Plugin not found after status update: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/plugin-loader.ts","lineNumber":2029,"sourceCode":"          \"Cannot loadSingle: no PluginRuntimeServices provided. \" +\n            \"Pass runtime services as the third argument to pluginLoader().\",\n        );\n      }\n\n      const plugin = (await registry.getById(pluginId)) as PluginRecord | null;\n      if (!plugin) {\n        throw new Error(`Plugin not found: ${pluginId}`);\n      }\n\n      // If the plugin is in 'installed' status, transition it to 'ready' first.\n      // lifecycleManager.load() transitions the status AND activates the plugin\n      // via activateReadyPlugin() → loadSingle() (recursive call with 'ready'\n      // status) → activatePlugin(). We must NOT call activatePlugin() again here,\n      // as that would double-start the worker and duplicate registrations.\n      if (plugin.status === \"installed\") {\n        await runtimeServices.lifecycleManager.load(pluginId);\n        const updated = (await registry.getById(pluginId)) as PluginRecord | null;\n        if (!updated) throw new Error(`Plugin not found after status update: ${pluginId}`);\n        return {\n          plugin: updated,\n          success: true,\n          registered: { worker: true, eventSubscriptions: 0, jobs: 0, webhooks: 0, tools: 0 },\n        };\n      }\n\n      if (plugin.status !== \"ready\") {\n        throw new Error(\n          `Cannot load plugin in status '${plugin.status}'. ` +\n            `Plugin must be in 'installed' or 'ready' status.`,\n        );\n      }\n\n      return activatePlugin(plugin, {\n        markErrorOnFailure: options.markErrorOnFailure ?? true,\n      });\n    },","sourceCodeStart":2011,"sourceCodeEnd":2047,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/server/src/services/plugin-loader.ts#L2011-L2047","documentation":"Post-update consistency guard in the plugin status transition path: after updating the plugin's status, registry.getById no longer finds the row. Defensive check against concurrent delete during enable/disable/load flows; the racing deletion is at fault.","triggerScenarios":"Thrown at server/src/services/plugin-loader.ts:2029 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["The plugin disappeared during the status update (concurrent uninstall). Re-check the plugin list and retry against an existing plugin."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"120ae5428fa29bee300bcf806491cd4d965fbb7c","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}