{"record":{"id":"0fcf0f2f094481ec","repo":"jackwener/OpenCLI","slug":"could-not-find-package-json-above-startfile","errorCode":null,"errorMessage":"Could not find package.json above ${startFile}","messagePattern":"Could not find package\\.json above (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/package-paths.ts","lineNumber":16,"sourceCode":"import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nexport interface PackageJsonLike {\n  bin?: string | Record<string, string>;\n  main?: string;\n}\n\nexport function findPackageRoot(startFile: string, fileExists: (candidate: string) => boolean = fs.existsSync): string {\n  let dir = path.dirname(startFile);\n\n  while (true) {\n    if (fileExists(path.join(dir, 'package.json'))) return dir;\n    const parent = path.dirname(dir);\n    if (parent === dir) {\n      throw new Error(`Could not find package.json above ${startFile}`);\n    }\n    dir = parent;\n  }\n}\n\nexport function getBuiltEntryCandidates(\n  packageRoot: string,\n  readFile: (filePath: string) => string = (filePath) => fs.readFileSync(filePath, 'utf-8'),\n): string[] {\n  const candidates: string[] = [];\n  try {\n    const pkg = JSON.parse(readFile(path.join(packageRoot, 'package.json'))) as PackageJsonLike;\n\n    if (typeof pkg.bin === 'string') {\n      candidates.push(path.join(packageRoot, pkg.bin));\n    } else if (pkg.bin && typeof pkg.bin === 'object' && typeof pkg.bin.opencli === 'string') {\n      candidates.push(path.join(packageRoot, pkg.bin.opencli));\n    }","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/src/package-paths.ts#L1-L34","documentation":"findPackageRoot() walks upward from startFile's directory looking for a package.json to identify the package root. If it reaches the filesystem root (parent === dir) without finding one, it throws this Error. The library relies on the package root to locate built assets such as the builtin CLIs directory.","triggerScenarios":"Calling findPackageRoot (directly or via PACKAGE_ROOT/packageRoot/projectRoot/BUILTIN_CLIS/defaultBuiltinClisDir) with a startFile path outside any package — e.g. inside /tmp, a bare system directory, a deployed bundle that strips package.json, or a deleted/moved project without package.json at any ancestor level.","commonSituations":"Running from a global install or standalone binary, container images built with `--no-package-json` pruning, monorepo code copied to a scratch dir, tests running with a tmp cwd outside the repo, or packaged apps (pkg/nexe) that virtualize the filesystem.","solutions":["Ensure a package.json exists at the project root and in every ancestor directory between startFile and the root.","If bundling/packaging, include package.json in the output alongside the entry file.","Run the code from within the installed package directory rather than a copied-out script.","In containers, keep package.json in the image next to the built sources."],"exampleFix":"// before (docker prune step)\nRUN rm -rf /app/package.json\n// after\nRUN cp /app/package.json /dist/  # or simply keep it in place","handlingStrategy":"try-catch","validationCode":"import fs from 'node:fs';\nimport path from 'node:path';\nfunction hasPackageJsonAbove(startFile) {\n  let dir = path.dirname(path.resolve(startFile));\n  while (true) {\n    if (fs.existsSync(path.join(dir, 'package.json'))) return true;\n    const parent = path.dirname(dir);\n    if (parent === dir) return false;\n    dir = parent;\n  }\n}\n// if (!hasPackageJsonAbove(__filename)) fail early with a clear deployment error","typeGuard":null,"tryCatchPattern":"let projectRoot;\ntry {\n  projectRoot = findPackageRoot(__filename);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Could not find package.json above')) {\n    projectRoot = process.env.APP_ROOT ?? process.cwd();\n    logger.warn(`No package.json found; assuming project root ${projectRoot}`);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always ship package.json with your bundled/deployed code (check Docker COPY scope and bundler externals).","Run the app from inside the installed package directory; don't copy entry files to scratch dirs.","For packaged binaries (pkg/nexe) or exotic filesystems, configure the library's root explicitly if it offers one.","Smoke-test in the deployment image — the error only appears at runtime in the target filesystem layout."],"tags":["filesystem","module-resolution","packaging"],"backgroundTag":"package-json-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}