{"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/f9245100cf0d31d96628804ead485f6bf226e55a/packages/turbo-workspaces/src/utils.ts#L51-L87","documentation":"The same getPackageJson() helper: when readJsonSync fails because JSON.parse cannot parse the file, the error carries code EJSONPARSE and is converted to ConvertError `failed to parse \"package.json\" at <root>` (type package_json-parse_error). The file exists but is not valid JSON.","triggerScenarios":"package.json containing JSON5 syntax (comments, trailing commas, unquoted keys), a UTF-8 BOM, single-quoted strings, or a file truncated mid-write; unresolved git merge conflict markers left in the manifest.","commonSituations":"Hand-editing package.json and pasting commented JSON; a CI job or codegen writing the file non-atomically; a partially resolved merge; an editor auto-inserting trailing commas.","solutions":["Validate the file: node -e \"JSON.parse(require('fs').readFileSync('package.json','utf8'))\" to get the exact offset","Remove comments, trailing commas, and BOM; quote all keys","Restore a known-good version with git checkout -- package.json if the breakage came from a merge or bad write"],"exampleFix":"// before (invalid: comment + trailing comma)\n{\n  // workspace config\n  \"name\": \"monorepo\",\n  \"private\": true,\n}\n// after\n{\n  \"name\": \"monorepo\",\n  \"private\": true\n}","handlingStrategy":"validation","validationCode":"import { readFileSync } from \"node:fs\";\nconst raw = readFileSync(manifestPath, \"utf8\").replace(/^\\uFEFF/, \"\");\ntry {\n  JSON.parse(raw);\n} catch (e) {\n  throw new Error(`package.json is not valid JSON: ${(e as Error).message}`);\n}","typeGuard":"function isConvertError(e: unknown): e is { type: string } {\n  return typeof e === \"object\" && e !== null && \"type\" in e;\n}","tryCatchPattern":"try {\n  await readWorkspace(args);\n} catch (e) {\n  if (isConvertError(e) && e.type === \"package_json-parse_error\") {\n    // JSON.parse the file yourself to get the line/column, fix the syntax, retry\n  } else {\n    throw e;\n  }\n}","preventionTips":["Never put comments or trailing commas in package.json — use JSON strictly","Write manifests atomically (write temp file, then rename) in codegen/CI scripts","Resolve merge conflicts in package.json before running workspace tools"],"tags":["package-json","json","parse-error","workspace"],"backgroundTag":"package-json-parse-error","analyzedSha":"f9245100cf0d31d96628804ead485f6bf226e55a","analyzedAt":"2026-08-17T10:46:15.696Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}