{"record":{"id":"2e3770dd6cdeb115","repo":"vercel/turborepo","slug":"package-json-missing","errorCode":"package_json-missing","errorMessage":"no \"package.json\" found at ${workspaceRoot}","messagePattern":"no \"package\\.json\" found at (.+?)","errorType":"exception","errorClass":"ConvertError","httpStatus":null,"severity":"error","filePath":"packages/turbo-workspaces/src/utils.ts","lineNumber":64,"sourceCode":"  \"pnpm\",\n  \"yarn\",\n  \"bun\",\n  \"nub\",\n  \"aube\"\n]);\n\nfunction getPackageJson({\n  workspaceRoot\n}: {\n  workspaceRoot: string;\n}): PackageJson {\n  const packageJsonPath = path.join(workspaceRoot, \"package.json\");\n  try {\n    return readJsonSync(packageJsonPath, \"utf8\") as PackageJson;\n  } catch (err) {\n    if (err && typeof err === \"object\" && \"code\" in err) {\n      if (err.code === \"ENOENT\") {\n        throw new ConvertError(`no \"package.json\" found at ${workspaceRoot}`, {\n          type: \"package_json-missing\"\n        });\n      }\n      if (err.code === \"EJSONPARSE\") {\n        throw new ConvertError(\n          `failed to parse \"package.json\" at ${workspaceRoot}`,\n          {\n            type: \"package_json-parse_error\"\n          }\n        );\n      }\n    }\n    throw new Error(\n      `unexpected error reading \"package.json\" at ${workspaceRoot}`\n    );\n  }\n}\n","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/vercel/turborepo/blob/9f94a7d215b3881942527dd526afa3fc650869d5/packages/turbo-workspaces/src/utils.ts#L46-L82","documentation":"Thrown by getPackageJson() in turbo-workspaces (utils.ts) when readJsonSync fails with ENOENT: the root passed as workspaceRoot contains no package.json. ConvertError type \"package_json-missing\" with the offending path in the message. Because every manager's detect() reads package.json (via getWorkspacePackageManager), this usually fires during detection - before any \"could not determine package manager\" result - for the first manager probed (aube) and propagates out of getWorkspaceDetails/convert.","triggerScenarios":"Calling getWorkspaceDetails({ root }) / convert({ root, to }) with a directory that exists but has no package.json (empty dir, repo root above the JS project, a directory arg pointing at a folder that only holds docs); also reached from MANAGERS.<m>.read/create/remove when the workspaceRoot's package.json was deleted between detection and the call.","commonSituations":"Invoking the migrate/convert CLI from the wrong directory (git toplevel instead of the package root); scripts that resolve the project root incorrectly (using process.cwd() inside a nested bin); fresh clones of subdirectories via sparse checkout that skipped package.json; build pipelines that copy sources but exclude package.json.","solutions":["Verify the path in the error message - run `ls <workspaceRoot>/package.json`; if missing, point root at the directory that actually owns the project's package.json","If the project legitimately has no manifest yet, create one first (`npm init -y` or copy the original package.json from VCS) and retry","When scripting, resolve the root from the nearest package.json instead of cwd: walk up until you find one, or use the value the error prints to correct the argument","Re-commit package.json if sparse checkout, .gitignore, or a Docker COPY pattern dropped it"],"exampleFix":"// before - root guessed from cwd, may not contain a manifest\nawait getWorkspaceDetails({ root: process.cwd() });\n\n// after - anchor the root at the directory that owns package.json\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nfunction findWorkspaceRoot(start: string): string {\n  let dir = path.resolve(start);\n  while (!existsSync(path.join(dir, \"package.json\"))) {\n    const parent = path.dirname(dir);\n    if (parent === dir) throw new Error(`no package.json above ${start}`);\n    dir = parent;\n  }\n  return dir;\n}\nawait getWorkspaceDetails({ root: findWorkspaceRoot(process.cwd()) });","handlingStrategy":"validation","validationCode":"import { existsSync } from \"node:fs\";\nimport path from \"node:path\";\n\nconst packageJsonPath = path.join(workspaceRoot, \"package.json\");\nif (!existsSync(packageJsonPath)) {\n  throw new Error(`${packageJsonPath} does not exist - pass the directory that owns a package.json`);\n}\nconst details = await getWorkspaceDetails({ root: workspaceRoot });","typeGuard":"import { ConvertError } from \"turbo-workspaces\";\n\nfunction isPackageJsonMissing(err: unknown): err is ConvertError {\n  return err instanceof ConvertError && err.type === \"package_json-missing\";\n}","tryCatchPattern":"try {\n  const details = await getWorkspaceDetails({ root });\n} catch (err) {\n  if (err instanceof ConvertError && err.type === \"package_json-missing\") {\n    console.error(`No package.json at the root you passed. cd into (or pass) the project root and retry.`);\n    process.exit(1);\n  } else {\n    throw err;\n  }\n}","preventionTips":["Resolve the workspace root by walking up from cwd to the nearest package.json instead of trusting cwd","Keep package.json committed and never gitignore it","In Docker/CI, verify the COPY/include patterns ship package.json","Assert existence in scripts before invoking workspace tooling"],"tags":["package-json","filesystem","workspace-root","detection"],"backgroundTag":"missing-package-json","analyzedSha":"9f94a7d215b3881942527dd526afa3fc650869d5","analyzedAt":"2026-08-16T19:47:29.531Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}