can1357/oh-my-pi · error · Error

Failed to install ${packageName}: ${stderr}

Error message

Failed to install ${packageName}: ${stderr}

What it means

installPlugin spawns the package manager to install the requested plugin and waits for exit plus collected stdout/stderr. A non-zero exit code throws 'Failed to install <packageName>: <stderr>', surfacing the package manager's stderr as the cause.

Source

Thrown at packages/coding-agent/src/extensibility/plugins/installer.ts:64

	// Run npm install in plugins directory
	const proc = Bun.spawn(["bun", "install", packageName], {
		cwd: PLUGINS_DIR,
		stdin: "ignore",
		stdout: "pipe",
		stderr: "pipe",
		windowsHide: true,
	});

	// Drain both pipes concurrently with proc.exited to avoid a pipe-buffer
	// deadlock if bun install floods stdout/stderr.
	const [exitCode, , stderr] = await Promise.all([
		proc.exited,
		new Response(proc.stdout).text(),
		new Response(proc.stderr).text(),
	]);
	if (exitCode !== 0) {
		throw new Error(`Failed to install ${packageName}: ${stderr}`);
	}

	// Extract the actual package name (without version specifier) for path lookup
	const actualName = extractPackageName(packageName);

	// Read the installed package's package.json
	const pkgPath = path.join(PLUGINS_DIR, "node_modules", actualName, "package.json");
	const pkgFile = Bun.file(pkgPath);
	if (!(await pkgFile.exists())) {
		throw new Error(`Package installed but package.json not found at ${pkgPath}`);
	}

	const pkg = await pkgFile.json();

	return {
		name: pkg.name,
		version: pkg.version,
		path: path.join(PLUGINS_DIR, "node_modules", actualName),

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the stderr in the message — it contains the package manager's actual reason.
  2. Verify the package exists: `npm view <packageName>` or check the registry in a browser.
  3. Check network/proxy access to the registry and any required auth tokens (.npmrc).
  4. Install manually with `bun add <packageName>` in the plugins dir to reproduce and debug the exact failure.

Example fix

// before: unresolvable version
await installPlugin("omp-plugin@^99.0.0")
// after
await installPlugin("omp-plugin@^1.0.0")
Defensive patterns

Strategy: retry

Validate before calling

const view = Bun.spawnSync(["npm", "view", packageName, "version"], { stdout: "pipe", stderr: "pipe" });
if (view.exitCode !== 0) {
  throw new Error(`Package not resolvable: ${packageName} (${view.stderr.toString().trim()})`);
}
await installPlugin(packageName);

Try / catch

try {
  await installPlugin(pkg);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Failed to install")) {
    const transient = /ETIMEDOUT|ECONNRESET|network/i.test(err.message);
    if (transient) await backoffRetry(() => installPlugin(pkg), 3);
    else throw new Error(`Install failed permanently: ${err.message}`);
  } else throw err;
}

Prevention

When it happens

Trigger: bun/npm install exits non-zero: package doesn't exist in the registry, no network, version specifier unresolvable, auth required for a private registry, or peer-dependency conflicts.

Common situations: Typo'd package name (404 Not Found); offline/CI without registry access; private registry packages without an auth token; incompatible engine/version constraints; proxy blocks registry.npmjs.org.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/80516fb0456a5a39. Report an issue: GitHub.