{"record":{"id":"26ffa0bfcdbfac52","repo":"vercel/turborepo","slug":"package-json-parse-error","errorCode":"package_json-parse_error","errorMessage":"failed to parse \"package.json\" at ${workspaceRoot}","messagePattern":"failed to parse \"package\\.json\" at (.+?)","errorType":"exception","errorClass":"ConvertError","httpStatus":null,"severity":"error","filePath":"packages/turbo-workspaces/src/utils.ts","lineNumber":69,"sourceCode":"]);\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\nfunction getWorkspacePackageManager({\n  workspaceRoot\n}: {\n  workspaceRoot: string;\n}): PackageManager | undefined {","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/vercel/turborepo/blob/9f94a7d215b3881942527dd526afa3fc650869d5/packages/turbo-workspaces/src/utils.ts#L51-L87","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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","Fix the file: remove comments and trailing commas, quote keys and strings with double quotes, resolve any merge-conflict markers","If a workspace (not root) package.json is broken, the fix is the same - the error message names the workspaceRoot containing it","Add a CI step that JSON.parses every package.json (e.g. a lint script) so malformed manifests fail before migration runs"],"exampleFix":"// before - package.json (trailing comma + comment, EJSONPARSE)\n{\n  \"name\": \"monorepo\",\n  // managed by tools\n  \"private\": true,\n}\n\n// after - strict JSON\n{\n  \"name\": \"monorepo\",\n  \"private\": true\n}","handlingStrategy":"validation","validationCode":"import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\nconst raw = readFileSync(path.join(workspaceRoot, \"package.json\"), \"utf8\");\ntry {\n  JSON.parse(raw); // surfaces line/column before turbo-workspaces throws\n} catch (e) {\n  throw new Error(`package.json is not valid JSON: ${(e as Error).message}`);\n}\nconst details = await getWorkspaceDetails({ root: workspaceRoot });","typeGuard":"import { ConvertError } from \"turbo-workspaces\";\n\nfunction isPackageJsonParseError(err: unknown): err is ConvertError {\n  return err instanceof ConvertError && err.type === \"package_json-parse_error\";\n}","tryCatchPattern":"try {\n  const details = await getWorkspaceDetails({ root });\n} catch (err) {\n  if (err instanceof ConvertError && err.type === \"package_json-parse_error\") {\n    // Re-parse locally to show the developer the exact position\n    try { JSON.parse(readFileSync(path.join(root, \"package.json\"), \"utf8\")); }\n    catch (e) { console.error(`Fix package.json: ${(e as Error).message}`); }\n    process.exit(1);\n  } else throw err;\n}","preventionTips":["Treat package.json as strict JSON: no comments, no trailing commas, double quotes only","Run `node -e \"JSON.parse(...)\"` or jsonlint over all package.json files in CI","Check for merge-conflict markers after every git merge that touches manifests","Use `npm pkg set` / package-manager commands instead of hand-editing to mutate package.json"],"tags":["package-json","json-parse","validation","workspace-root"],"backgroundTag":"malformed-package-json","analyzedSha":"9f94a7d215b3881942527dd526afa3fc650869d5","analyzedAt":"2026-08-16T19:47:29.531Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}