vercel/turborepo · error · ConvertError

package_json-parse_error

package_json-parse_error

Error message

failed to parse "package.json" at ${workspaceRoot}

What it means

Thrown by getPackageJson() in turbo-workspaces when readJsonSync fails with code EJSONPARSE: a package.json exists at workspaceRoot but is not valid JSON (fs-extra attaches EJSONPARSE to JSON.parse failures). ConvertError type "package_json-parse_error" with the path in the message. It fires from any manager's detect() as well as read/create/remove, and also for individual workspace package.json files discovered by glob in expandWorkspaces/getWorkspaceInfo.

Source

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

]);

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}`
    );
  }
}

function getWorkspacePackageManager({
  workspaceRoot
}: {
  workspaceRoot: string;
}): PackageManager | undefined {

View on GitHub (pinned to 9f94a7d215)

Solutions

  1. Locate the exact syntax error: `node -e "JSON.parse(require('fs').readFileSync('<path>','utf8'))"` (or `npx jsonlint <path>`) - Node prints the line/column of the first bad token
  2. Fix the file: remove comments and trailing commas, quote keys and strings with double quotes, resolve any merge-conflict markers
  3. If a workspace (not root) package.json is broken, the fix is the same - the error message names the workspaceRoot containing it
  4. Add a CI step that JSON.parses every package.json (e.g. a lint script) so malformed manifests fail before migration runs

Example fix

// before - package.json (trailing comma + comment, EJSONPARSE)
{
  "name": "monorepo",
  // managed by tools
  "private": true,
}

// after - strict JSON
{
  "name": "monorepo",
  "private": true
}
Defensive patterns

Strategy: validation

Validate before calling

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

const raw = readFileSync(path.join(workspaceRoot, "package.json"), "utf8");
try {
  JSON.parse(raw); // surfaces line/column before turbo-workspaces throws
} catch (e) {
  throw new Error(`package.json is not valid JSON: ${(e as Error).message}`);
}
const details = await getWorkspaceDetails({ root: workspaceRoot });

Type guard

import { ConvertError } from "turbo-workspaces";

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

Try / catch

try {
  const details = await getWorkspaceDetails({ root });
} catch (err) {
  if (err instanceof ConvertError && err.type === "package_json-parse_error") {
    // Re-parse locally to show the developer the exact position
    try { JSON.parse(readFileSync(path.join(root, "package.json"), "utf8")); }
    catch (e) { console.error(`Fix package.json: ${(e as Error).message}`); }
    process.exit(1);
  } else throw err;
}

Prevention

When it happens

Trigger: Root or workspace package.json containing JSONC conveniences - comments, trailing commas, single-quoted strings, unquoted keys; merge conflict markers (<<<<<<< ======= >>>>>>>) left in after a bad merge; a truncated file from a crashed editor/write (save interrupted, disk full); a BOM or smart quotes pasted from a chat/doc.

Common situations: Developers pasting commented config into package.json because their editor's JSONC mode accepts it; git merges that were "resolved" by keeping both conflict blocks; tools that append dependencies non-atomically and were killed mid-write; monorepos where one nested package's package.json is malformed and only fails when the migration globs into it.

Understand the failure class

Related errors


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