{"record":{"id":"feb542d600cd75b2","repo":"can1357/oh-my-pi","slug":"package-json-not-found-at-absolutepath-feb542","errorCode":null,"errorMessage":"package.json not found at ${absolutePath}","messagePattern":"package\\.json not found at (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/extensibility/plugins/manager.ts","lineNumber":779,"sourceCode":"\t\t\t\tplugins.push(plugin);\n\t\t\t}\n\t\t}\n\n\t\treturn plugins;\n\t}\n\n\t/**\n\t * Link a local plugin for development.\n\t */\n\tasync link(localPath: string): Promise<InstalledPlugin> {\n\t\tconst absolutePath = path.resolve(this.#cwd, localPath);\n\n\t\tconst pkgFilePath = path.join(absolutePath, \"package.json\");\n\t\tlet pkg: { name?: string; version: string; omp?: PluginManifest; pi?: PluginManifest };\n\t\ttry {\n\t\t\tpkg = await Bun.file(pkgFilePath).json();\n\t\t} catch (err) {\n\t\t\tif (isEnoent(err)) throw new Error(`package.json not found at ${absolutePath}`);\n\t\t\tthrow err;\n\t\t}\n\t\tif (!pkg.name) {\n\t\t\tthrow new Error(\"package.json must have a name field\");\n\t\t}\n\n\t\tawait this.#ensurePluginsDir();\n\n\t\tconst linkPath = path.join(getPluginsNodeModules(), pkg.name);\n\n\t\t// Handle scoped packages\n\t\tif (pkg.name.startsWith(\"@\")) {\n\t\t\tconst scopeDir = path.join(getPluginsNodeModules(), pkg.name.split(\"/\")[0]);\n\t\t\tawait fs.promises.mkdir(scopeDir, { recursive: true });\n\t\t}\n\n\t\t// Remove existing\n\t\ttry {","sourceCodeStart":761,"sourceCodeEnd":797,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/extensibility/plugins/manager.ts#L761-L797","documentation":"PluginManager.loadFromPath (or similar install entry) reads <pluginDir>/package.json to get the plugin's name, version, and optional omp/pi manifest. If the file does not exist (ENOENT), it throws this error rather than a raw JSON parse error, so the developer knows the plugin directory itself lacks a package.json. It is a guard against installing a directory that is not a valid npm-style plugin package.","triggerScenarios":"Calling a PluginManager public method that installs/links a plugin from a local path where no package.json exists at the directory root; pointing the installer at a source folder, a git checkout root, or a typo'd directory name.","commonSituations":"Typo in the plugin path; running the installer against a repo subdirectory instead of the package root; a plugin authored without package.json; path resolved relative to the wrong working directory.","solutions":["Verify the directory actually contains package.json at its root (ls <dir>/package.json).","Correct the path passed to the install/load call — point at the package root, not a parent or subfolder.","If authoring a plugin, add a package.json with name, version, and an omp (or pi) manifest field.","Check the working directory relative to which the path was resolved."],"exampleFix":"// before\nawait manager.installFromPath(\"./my-plugin/dist\"); // no package.json in dist\n// after\nawait manager.installFromPath(\"./my-plugin\"); // package root","handlingStrategy":"validation","validationCode":"import * as fs from \"node:fs\";\nconst pkgPath = path.join(pluginDir, \"package.json\");\nif (!fs.existsSync(pkgPath)) {\n  throw new Error(`Not a plugin package: ${pkgPath} missing`);\n}","typeGuard":"function hasPackageJson(dir: string): boolean {\n  try { return fs.statSync(path.join(dir, \"package.json\")).isFile(); }\n  catch { return false; }\n}","tryCatchPattern":"try {\n  await manager.installFromPath(dir);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"package.json not found\")) {\n    console.error(`Directory ${dir} is not a plugin package root`);\n  } else throw err;\n}","preventionTips":["Always pass the package root directory, not a parent or build-output subfolder","Check for package.json existence before invoking install APIs","Scaffold plugins from a template that includes package.json","Resolve relative paths against a known base directory"],"tags":["plugins","filesystem","missing-file","package-json"],"backgroundTag":"missing-file","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}