{"record":{"id":"9af493efb44ecac1","repo":"decolua/9router","slug":"install-finished-but-package-is-missing-see-inst","errorCode":null,"errorMessage":"install finished but package is missing — see install.log","messagePattern":"install finished but package is missing — see install\\.log","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/lib/pxpipe/install.js","lineNumber":111,"sourceCode":"      cwd: PXPIPE_DIR,\n      stdio: [\"ignore\", outFd, outFd],\n      windowsHide: true,\n      env: { ...process.env, PATH: EXTENDED_PATH },\n    });\n    const timer = setTimeout(() => {\n      child.kill(\"SIGKILL\");\n      reject(new Error(\"npm install timed out after 5 minutes — see install.log\"));\n    }, INSTALL_TIMEOUT_MS);\n    child.once(\"error\", (e) => { clearTimeout(timer); reject(e); });\n    child.once(\"exit\", (code) => {\n      clearTimeout(timer);\n      if (code === 0) resolve();\n      else reject(new Error(`npm install exited with code ${code} — see install.log`));\n    });\n  }).finally(() => fs.closeSync(outFd));\n\n  const info = getInstallInfo();\n  if (!info.installed) throw new Error(\"install finished but package is missing — see install.log\");\n  return info;\n}\n\nexport function getInstallLogTail(maxLines = 200) {\n  try {\n    if (!fs.existsSync(INSTALL_LOG)) return \"\";\n    const lines = fs.readFileSync(INSTALL_LOG, \"utf8\").split(/\\r?\\n/).filter(Boolean);\n    return lines.slice(-maxLines).join(\"\\n\");\n  } catch {\n    return \"\";\n  }\n}\n","sourceCodeStart":93,"sourceCodeEnd":124,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/pxpipe/install.js#L93-L124","documentation":"Thrown by runInstall after `npm install <pxpipe-package>@latest` exits with code 0 (npm reported success) but getInstallInfo() still cannot find the installed package in the PXPIPE host directory. It guards against installs that 'succeed' yet leave nothing loadable — e.g. npm wrote to a different location, the package resolved to an empty/failed install, or the install-info probe looks in the wrong place. The install.log tail (getInstallLogTail) is the diagnostic source.","triggerScenarios":"npm install exits 0 but the expected package directory/entry (checked by getInstallInfo/libraryEntry) is absent under PXPIPE_DIR — for example npm installed the package into a parent node_modules because PXPIPE_DIR sits inside a workspace, or the package name/layout changed upstream so the expected entry no longer exists.","commonSituations":"Running under a monorepo where npm hoists the package outside the host dir; a read-only or redirected npm prefix/cache; a partial/corrupted npm cache giving a phantom success; pxpipe upstream renamed its package entry point; disk-full or antivirus interference; running the server from a different cwd so PXPIPE_DIR resolves elsewhere.","solutions":["Read the install log via getInstallLogTail() (the install.log in the pxpipe dir) to see what npm actually did.","Check PXPIPE_DIR for node_modules/<package> and verify its package.json main/exports still point at the expected entry (transformAnthropicMessages).","Delete PXPIPE_DIR (including package-lock.json) and re-run the install so npm does a clean resolution instead of reusing a broken tree.","If npm hoisted the package (monorepo), run the install outside any workspace or pin the install to the host dir (e.g. --install-links / --prefix PXPIPE_DIR, or set workspaces=false in the host package.json).","Clear the npm cache (npm cache verify / npm cache clean --force) if npm repeatedly reports success without installing, then retry Repair in the dashboard."],"exampleFix":"// before\nfs.writeFileSync(pkgJson, JSON.stringify({ name: \"9router-pxpipe-host\", private: true }, null, 2));\n// after: keep npm from hoisting into a parent workspace\nfs.writeFileSync(pkgJson, JSON.stringify({ name: \"9router-pxpipe-host\", private: true, workspaces: false }, null, 2));\n// and install with an explicit prefix:\n// spawn(npm, [\"install\", `${PXPIPE_PACKAGE}@latest`, \"--prefix\", PXPIPE_DIR, ...])","handlingStrategy":"validation","validationCode":"import fs from \"fs\";\nimport path from \"path\";\nfunction isPxpipeInstalled(pxpipeDir, pkgName) {\n  const pkgPath = path.join(pxpipeDir, \"node_modules\", pkgName, \"package.json\");\n  try {\n    const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf8\"));\n    return Boolean(pkg.main || pkg.exports);\n  } catch { return false; }\n}\n// run before loadPxpipe(); if false, reinstall or inspect getInstallLogTail()","typeGuard":null,"tryCatchPattern":"try {\n  await installPxpipe();\n} catch (e) {\n  if (e.message.includes(\"install finished but package is missing\")) {\n    console.error(\"pxpipe install incomplete:\", getInstallLogTail(50));\n    // wipe PXPIPE_DIR and retry once\n  } else throw e;\n}","preventionTips":["After npm exits 0, assert node_modules/<pkg> exists before declaring success (install.log tail is the evidence source).","Avoid installing inside a monorepo workspace root — npm hoists the package out of the host dir; set workspaces:false or use --prefix.","Clear PXPIPE_DIR (incl. package-lock.json) on reinstall to avoid stale/partial trees.","Watch disk space and npm cache health (npm cache verify) in CI/sandboxed environments.","Pin the pxpipe version instead of @latest so upstream renames can't silently change the layout."],"tags":["npm","install","filesystem","pxpipe"],"backgroundTag":"package-install-missing","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}