{"record":{"id":"a9a8e5edabcca846","repo":"diegosouzapw/OmniRoute","slug":"plugin-name-is-already-installed-existing","errorCode":null,"errorMessage":"Plugin '${name}' is already installed (${existing.version}) and source version ${manifest.version} is not newer","messagePattern":"Plugin '(.+?)' is already installed \\((.+?)\\) and source version (.+?) is not newer","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/lib/plugins/manager.ts","lineNumber":173,"sourceCode":"      : await scanPluginDir(sourceDir);\n\n    if (plugins.length === 0) {\n      throw new Error(\n        `No valid plugin found in ${sourceDir}: ${errors.map((e) => e.error).join(\", \")}`\n      );\n    }\n\n    const discovered = plugins[0];\n    const { name, manifest, pluginDir: srcDir } = discovered;\n\n    // If already installed, auto-upgrade when source is strictly newer; reject otherwise.\n    if (pluginExists(name)) {\n      const existing = getPluginByName(name)!;\n      if (compareSemver(manifest.version, existing.version) > 0) {\n        // Source is newer — delegate to upgrade()\n        return this.upgrade(sourceDir);\n      }\n      throw new Error(\n        `Plugin '${name}' is already installed (${existing.version}) and source version ${manifest.version} is not newer`\n      );\n    }\n\n    // CRITICAL-3: Copy to staging dir first, validate, then rename atomically.\n    const destDir = join(this.pluginDir, name);\n    const stagingDir = `${destDir}.staging-${randomUUID()}`;\n    await mkdir(dirname(destDir), { recursive: true });\n    // Reaching here means the plugin is not DB-registered (the pluginExists()\n    // guard above returns/throws otherwise). A destDir still present on disk is\n    // therefore orphaned (e.g. a crash mid-uninstall left files behind) and would\n    // make the atomic rename below fail with ENOTEMPTY — remove it first, guarded\n    // by path containment so we never rm outside the plugin directory.\n    assertWithinPluginDir(this.pluginDir, destDir);\n    await rm(destDir, { recursive: true, force: true }).catch(() => {});\n    await cp(srcDir, stagingDir, { recursive: true });\n\n    try {","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/diegosouzapw/OmniRoute/blob/a179ffed5bb2e0b883b9ae7214ce8717b2a94c4d/src/lib/plugins/manager.ts#L155-L191","documentation":"Error \"Plugin '${name}' is already installed (${existing.version}) and source version ${manifest.version} is not newer\" thrown in diegosouzapw/OmniRoute.","triggerScenarios":"Thrown at src/lib/plugins/manager.ts:173 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":[],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"a179ffed5bb2e0b883b9ae7214ce8717b2a94c4d","analyzedAt":"2026-08-25T18:35:09.898Z","schemaVersion":2},"datasetVersion":"2026-08-25T21:54:21.419Z"}