vercel/turborepo · error · TransformError

Unable to read package.json

Error message

Unable to read package.json

What it means

Thrown by create-turbo's official-starter transform after it downloads and extracts a starter example: it reads the extracted root package.json with fs.readJsonSync to adjust the project name and turbo version. If that file is missing, unreadable, or not valid JSON, this non-fatal TransformError is thrown.

Source

Thrown at packages/create-turbo/src/transforms/official-starter.ts:54

  let metaJson: MetaJson | undefined;

  // 1. remove meta file (used for generating the examples page on turborepo.dev)
  try {
    metaJson = fs.readJsonSync(rootMetaJsonPath) as MetaJson;
    fs.rmSync(rootMetaJsonPath, { force: true });
  } catch (_err) {
    // do nothing
  }

  if (hasPackageJson) {
    let packageJsonContent: PackageJson | undefined;
    try {
      packageJsonContent = fs.readJsonSync(rootPackageJsonPath) as
        | PackageJson
        | undefined;
    } catch {
      throw new TransformError("Unable to read package.json", {
        transform: meta.name,
        fatal: false
      });
    }

    // if using the basic example, set the name to the project name (legacy behavior)
    if (packageJsonContent) {
      if (defaultExample) {
        packageJsonContent.name = prompts.projectName;
      }

      if (packageJsonContent.devDependencies?.turbo) {
        // if the user specified a turbo version, use that
        if (opts.turboVersion) {
          packageJsonContent.devDependencies.turbo = opts.turboVersion;
          // use the same version as the create-turbo invocation
        } else {
          // eslint-disable-next-line @typescript-eslint/no-var-requires -- Have to go get package.json

View on GitHub (pinned to 9f94a7d215)

Solutions

  1. Delete the partial output directory and simply re-run create-turbo (transient download/extraction failures are the most common cause)
  2. If using --example with a custom path, verify that path directly contains a valid package.json (test with `node -e "JSON.parse(require('fs').readFileSync('<path>/package.json','utf8'))"`)
  3. Check disk space and directory permissions, then retry
  4. Fall back to a known-good official example name (e.g. `--example basic`) to rule out the custom source

Example fix

# before
npx create-turbo@latest --example ./my-broken-example my-app
# after
npx create-turbo@latest --example basic my-app
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs';

function isValidExampleDir(dir: string): boolean {
  const pkg = `${dir}/package.json`;
  if (!fs.existsSync(pkg)) return false;
  try {
    JSON.parse(fs.readFileSync(pkg, 'utf8'));
    return true;
  } catch {
    return false;
  }
}
// run before: createTurbo({ example: myDir }) requires isValidExampleDir(myDir)

Try / catch

try {
  await createApp({ example });
} catch (err) {
  if (err instanceof TransformError && err.transform === meta.name) {
    // message 'Unable to read package.json': safest recovery is cleanup + one retry
    await fs.rm(targetDir, { recursive: true, force: true });
    return createApp({ example }); // one bounded retry, then surface
  }
  throw err;
}

Prevention

When it happens

Trigger: fs.readJsonSync(rootPackageJsonPath) throwing inside the transform: the starter extraction was incomplete (interrupted download/disk-full), a custom --example path has no root package.json, a permissions error, or the file contains malformed/truncated JSON.

Common situations: Flaky network cutting off example download mid-extract; passing --example a local directory or GitHub repo whose package.json sits in a subfolder; corporate proxies mangling tarballs; truncated files after a full disk.

Related errors


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