decolua/9router · error · Error

install finished but package is missing — see install.log

Error message

install finished but package is missing — see install.log

What it means

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.

Solutions

  1. Read the install log via getInstallLogTail() (the install.log in the pxpipe dir) to see what npm actually did.
  2. Check PXPIPE_DIR for node_modules/<package> and verify its package.json main/exports still point at the expected entry (transformAnthropicMessages).
  3. Delete PXPIPE_DIR (including package-lock.json) and re-run the install so npm does a clean resolution instead of reusing a broken tree.
  4. 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).
  5. Clear the npm cache (npm cache verify / npm cache clean --force) if npm repeatedly reports success without installing, then retry Repair in the dashboard.

Example fix

// before
fs.writeFileSync(pkgJson, JSON.stringify({ name: "9router-pxpipe-host", private: true }, null, 2));
// after: keep npm from hoisting into a parent workspace
fs.writeFileSync(pkgJson, JSON.stringify({ name: "9router-pxpipe-host", private: true, workspaces: false }, null, 2));
// and install with an explicit prefix:
// spawn(npm, ["install", `${PXPIPE_PACKAGE}@latest`, "--prefix", PXPIPE_DIR, ...])
Defensive patterns

Strategy: validation

Validate before calling

import fs from "fs";
import path from "path";
function isPxpipeInstalled(pxpipeDir, pkgName) {
  const pkgPath = path.join(pxpipeDir, "node_modules", pkgName, "package.json");
  try {
    const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
    return Boolean(pkg.main || pkg.exports);
  } catch { return false; }
}
// run before loadPxpipe(); if false, reinstall or inspect getInstallLogTail()

Try / catch

try {
  await installPxpipe();
} catch (e) {
  if (e.message.includes("install finished but package is missing")) {
    console.error("pxpipe install incomplete:", getInstallLogTail(50));
    // wipe PXPIPE_DIR and retry once
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/9af493efb44ecac1. Report an issue: GitHub.

Appendix: source

Thrown at src/lib/pxpipe/install.js:111

      cwd: PXPIPE_DIR,
      stdio: ["ignore", outFd, outFd],
      windowsHide: true,
      env: { ...process.env, PATH: EXTENDED_PATH },
    });
    const timer = setTimeout(() => {
      child.kill("SIGKILL");
      reject(new Error("npm install timed out after 5 minutes — see install.log"));
    }, INSTALL_TIMEOUT_MS);
    child.once("error", (e) => { clearTimeout(timer); reject(e); });
    child.once("exit", (code) => {
      clearTimeout(timer);
      if (code === 0) resolve();
      else reject(new Error(`npm install exited with code ${code} — see install.log`));
    });
  }).finally(() => fs.closeSync(outFd));

  const info = getInstallInfo();
  if (!info.installed) throw new Error("install finished but package is missing — see install.log");
  return info;
}

export function getInstallLogTail(maxLines = 200) {
  try {
    if (!fs.existsSync(INSTALL_LOG)) return "";
    const lines = fs.readFileSync(INSTALL_LOG, "utf8").split(/\r?\n/).filter(Boolean);
    return lines.slice(-maxLines).join("\n");
  } catch {
    return "";
  }
}

View on GitHub (pinned to 90b52e06ff)