vercel/turborepo · error · ConvertError

package_json-missing

package_json-missing

Error message

no "package.json" found at ${workspaceRoot}

What it means

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.

Source

Thrown at packages/turbo-workspaces/src/utils.ts:64

  "pnpm",
  "yarn",
  "bun",
  "nub",
  "aube"
]);

function getPackageJson({
  workspaceRoot
}: {
  workspaceRoot: string;
}): PackageJson {
  const packageJsonPath = path.join(workspaceRoot, "package.json");
  try {
    return readJsonSync(packageJsonPath, "utf8") as PackageJson;
  } catch (err) {
    if (err && typeof err === "object" && "code" in err) {
      if (err.code === "ENOENT") {
        throw new ConvertError(`no "package.json" found at ${workspaceRoot}`, {
          type: "package_json-missing"
        });
      }
      if (err.code === "EJSONPARSE") {
        throw new ConvertError(
          `failed to parse "package.json" at ${workspaceRoot}`,
          {
            type: "package_json-parse_error"
          }
        );
      }
    }
    throw new Error(
      `unexpected error reading "package.json" at ${workspaceRoot}`
    );
  }
}

View on GitHub (pinned to 9f94a7d215)

Solutions

  1. 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
  2. If the project legitimately has no manifest yet, create one first (`npm init -y` or copy the original package.json from VCS) and retry
  3. 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
  4. Re-commit package.json if sparse checkout, .gitignore, or a Docker COPY pattern dropped it

Example fix

// before - root guessed from cwd, may not contain a manifest
await getWorkspaceDetails({ root: process.cwd() });

// after - anchor the root at the directory that owns package.json
import { existsSync } from "node:fs";
import path from "node:path";
function findWorkspaceRoot(start: string): string {
  let dir = path.resolve(start);
  while (!existsSync(path.join(dir, "package.json"))) {
    const parent = path.dirname(dir);
    if (parent === dir) throw new Error(`no package.json above ${start}`);
    dir = parent;
  }
  return dir;
}
await getWorkspaceDetails({ root: findWorkspaceRoot(process.cwd()) });
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from "node:fs";
import path from "node:path";

const packageJsonPath = path.join(workspaceRoot, "package.json");
if (!existsSync(packageJsonPath)) {
  throw new Error(`${packageJsonPath} does not exist - pass the directory that owns a package.json`);
}
const details = await getWorkspaceDetails({ root: workspaceRoot });

Type guard

import { ConvertError } from "turbo-workspaces";

function isPackageJsonMissing(err: unknown): err is ConvertError {
  return err instanceof ConvertError && err.type === "package_json-missing";
}

Try / catch

try {
  const details = await getWorkspaceDetails({ root });
} catch (err) {
  if (err instanceof ConvertError && err.type === "package_json-missing") {
    console.error(`No package.json at the root you passed. cd into (or pass) the project root and retry.`);
    process.exit(1);
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of vercel/turborepo@9f94a7d215 (2026-08-16). Data as JSON: /api/errors/2e3770dd6cdeb115. Report an issue: GitHub.