{"record":{"id":"745db6ec04685d71","repo":"can1357/oh-my-pi","slug":"package-installed-but-package-json-not-found-at","errorCode":null,"errorMessage":"Package installed but package.json not found at ${pkgPath}","messagePattern":"Package installed but package\\.json not found at (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/extensibility/plugins/installer.ts","lineNumber":74,"sourceCode":"\t// Drain both pipes concurrently with proc.exited to avoid a pipe-buffer\n\t// deadlock if bun install floods stdout/stderr.\n\tconst [exitCode, , stderr] = await Promise.all([\n\t\tproc.exited,\n\t\tnew Response(proc.stdout).text(),\n\t\tnew Response(proc.stderr).text(),\n\t]);\n\tif (exitCode !== 0) {\n\t\tthrow new Error(`Failed to install ${packageName}: ${stderr}`);\n\t}\n\n\t// Extract the actual package name (without version specifier) for path lookup\n\tconst actualName = extractPackageName(packageName);\n\n\t// Read the installed package's package.json\n\tconst pkgPath = path.join(PLUGINS_DIR, \"node_modules\", actualName, \"package.json\");\n\tconst pkgFile = Bun.file(pkgPath);\n\tif (!(await pkgFile.exists())) {\n\t\tthrow new Error(`Package installed but package.json not found at ${pkgPath}`);\n\t}\n\n\tconst pkg = await pkgFile.json();\n\n\treturn {\n\t\tname: pkg.name,\n\t\tversion: pkg.version,\n\t\tpath: path.join(PLUGINS_DIR, \"node_modules\", actualName),\n\t\tmanifest: pkg.omp || pkg.pi || { version: pkg.version },\n\t\tenabledFeatures: null,\n\t\tenabled: true,\n\t};\n}\n\nexport async function uninstallPlugin(name: string): Promise<void> {\n\t// Validate package name\n\tvalidatePackageName(name);\n","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/extensibility/plugins/installer.ts#L56-L92","documentation":"installPlugin runs `bun install <pkg>` into the plugins directory, then reads the installed package's package.json to return plugin metadata (name, version, etc.). This error is thrown when bun install reported success (exit code 0) but the expected package.json at PLUGINS_DIR/node_modules/<name>/package.json does not exist. It signals an inconsistency between what bun claimed to install and what is actually on disk.","triggerScenarios":"installPlugin(packageName) completes bun install with exit code 0, but extractPackageName(packageName) yields a directory name that does not match where bun actually placed the package — e.g. the version specifier parses to a different name than installed, the package was deduped/hoisted, or the install was partially cleaned up before the exists() check.","commonSituations":"Installing a package whose name contains a version/tag that extractPackageName mishandles; a race where another process removes node_modules content; an aliased install spec (npm alias like `foo@npm:bar`) where the on-disk folder differs from the requested name; corrupted or interrupted install cache.","solutions":["Re-run the install (delete ~/.omp/plugins and reinstall) to rule out a stale/partial install","Verify the package name/spec is a plain npm name with optional semver, not an alias, git URL, or file path","Check that ~/.omp/plugins/node_modules/<extracted-name>/package.json exists manually to see what bun actually wrote","Update the CLI — extractPackageName may have a parsing bug for your spec format"],"exampleFix":"// before: alias/remote spec confuses path lookup\nawait installPlugin(\"my-plugin@npm:other-plugin@1.2.3\");\n// after: install the real package name\nawait installPlugin(\"other-plugin@1.2.3\");","handlingStrategy":"validation","validationCode":"import path from \"node:path\";\nconst pkgPath = path.join(agentDir, \"plugins\", \"node_modules\", extractPackageName(spec), \"package.json\");\nif (!(await Bun.file(pkgPath).exists())) {\n\tthrow new Error(`install target missing before/after install: ${pkgPath}`);\n}","typeGuard":"function isRecordWithPackageMeta(v: unknown): v is { name: string; version?: string } {\n\treturn typeof v === \"object\" && v !== null && \"name\" in v && typeof (v as { name: unknown }).name === \"string\";\n}","tryCatchPattern":"try {\n\tconst plugin = await installPlugin(spec);\n} catch (err) {\n\tif (err instanceof Error && err.message.includes(\"package.json not found\")) {\n\t\t// retry once after clearing partial install, or surface install-layout error\n\t}\n\tthrow err;\n}","preventionTips":["Use plain npm name+version specs; avoid aliases (`npm:`) and non-registry specs with installPlugin","After any install failure, clear ~/.omp/plugins/node_modules before retrying","Verify the package exists on the registry with the exact name beforehand"],"tags":["plugins","filesystem","npm-install","state-inconsistency"],"backgroundTag":"package-json-missing-after-install","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}