{"id":"970bf1dcbbce1093","repo":"prisma/prisma","slug":"manifestpath-not-valid-json-error-instanceo-970bf1","errorCode":null,"errorMessage":"${manifestPath}: not valid JSON (${error instanceof Error ? error.message : String(error)})","messagePattern":"(.+?): not valid JSON \\((.+?)\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skills/extension-author/prisma-next-extension-upgrade/upgrades/0.16-to-0.17/strip-sha256-hash-prefixes.ts","lineNumber":251,"sourceCode":"    return { path, status: 'already-clean' };\n  }\n  if (!dryRun) await writeFile(path, after, 'utf-8');\n  return { path, status: dryRun ? 'needs-fix' : 'fixed' };\n}\n\nasync function processSibling(path: string): Promise<Result> {\n  const raw = await readFile(path, 'utf-8');\n  return emit(path, raw, stripHashPrefixes(raw));\n}\n\nasync function processPackage(manifestPath: string): Promise<Result[]> {\n  const raw = await readFile(manifestPath, 'utf-8');\n\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(raw);\n  } catch (error) {\n    throw new Error(\n      `${manifestPath}: not valid JSON (${error instanceof Error ? error.message : String(error)})`,\n    );\n  }\n  if (!isJsonObject(parsed)) {\n    return [{ path: manifestPath, status: 'already-clean' }]; // not a manifest object\n  }\n\n  const packageDir = dirname(manifestPath);\n\n  // A complete on-disk migration package pairs `migration.json` with a sibling\n  // `ops.json` (the operations the hash is computed over); without it we cannot\n  // recompute the hash, so this is not a package we should touch.\n  const opsPath = join(packageDir, 'ops.json');\n  let opsRaw: string;\n  try {\n    opsRaw = await readFile(opsPath, 'utf-8');\n  } catch {\n    return [{ path: manifestPath, status: 'skipped-no-ops' }];","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/prisma/prisma/blob/1243cdffbec0506c595ac8fd5865fe258c336fa0/skills/extension-author/prisma-next-extension-upgrade/upgrades/0.16-to-0.17/strip-sha256-hash-prefixes.ts#L233-L269","documentation":"Thrown by the 0.16→0.17 extension-upgrade codemod (strip-sha256-hash-prefixes) when it locates a `migration.json` on disk and `JSON.parse(raw)` throws. The codemod walks the project tree for migration packages (a `migration.json` paired with a sibling `ops.json`) to strip the legacy `sha256:` hash prefix and recompute each manifest's `migrationHash`; before it can recompute it must parse the manifest, so a structurally-invalid file aborts the whole run. The trailing parenthesised message is Node's native JSON parse error, naming the position of the bad token.","triggerScenarios":"Running `pnpm exec tsx .../strip-sha256-hash-prefixes.ts` (with or without `--check`) from a project root where some `migration.json` cannot be parsed: a trailing comma, an unquoted key, a comment, a BOM, a truncated file, or literal merge-conflict markers (`<<<<<<<`) left in the bytes.","commonSituations":"An unresolved git merge/rebase conflict left conflict markers inside `migrations/<dir>/migration.json`; a previous codemod or editor write was interrupted mid-flush leaving a partial file; a hand-edited manifest with a JSON5-style trailing comma or `//` comment; a teammate committed a `.json5` renamed to `.json`.","solutions":["Open the file at the path printed in the message and fix the JSON syntax error at the offset/position given in the parenthesised parse error.","If the corruption is from a git merge conflict, resolve the conflict markers then re-run the codemod (it is idempotent).","If the manifest is disposable, restore it from a clean checkout (`git checkout -- <path>`) or re-generate it with the migration authoring tooling, then re-run.","Validate the file with a JSON linter (`pnpm exec tsx -e \"JSON.parse(require('fs').readFileSync('<path>','utf8'))\"`) before re-running."],"exampleFix":"// before — migrations/0001_init/migration.json\n{\n  \"from\": \"sha256:8ee1e7ce...\",\n  \"to\": \"sha256:059f3f35...\",\n  \"providedInvariants\": [],  // <- trailing comma / comment breaks JSON.parse\n}\n\n// after\n{\n  \"from\": \"sha256:8ee1e7ce...\",\n  \"to\": \"sha256:059f3f35...\",\n  \"providedInvariants\": []\n}","handlingStrategy":"try-catch","validationCode":"import { readFile } from 'node:fs/promises';\n\n// Pre-scan every migration.json / package.json before invoking the upgrade.\nasync function assertManifestsAreValidJson(paths: string[]): Promise<void> {\n  for (const manifestPath of paths) {\n    const raw = await readFile(manifestPath, 'utf-8');\n    try { JSON.parse(raw); }\n    catch (error) {\n      const msg = error instanceof Error ? error.message : String(error);\n      throw new Error(`Refusing to run upgrade: ${manifestPath} is not valid JSON (${msg})`);\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await runUpgradeScripts(projectRoot);\n} catch (error) {\n  if (error instanceof Error && error.message.includes(': not valid JSON (')) {\n    const offending = error.message.split(':')[0];\n    console.error(`Upgrade aborted: fix or regenerate ${offending}, then re-run.`);\n    process.exit(1);\n  }\n  throw error;\n}","preventionTips":["Never hand-edit migration.json or package.json; regenerate them via the CLI so they stay valid JSON.","Add a JSON linter or `git diff --check` to your pre-commit hook.","Commit only tool-generated migration artifacts.","Run `pnpm fixtures:check` before invoking upgrade scripts."],"tags":["codemod","json","migration","upgrade","extension-author"],"analyzedSha":"1243cdffbec0506c595ac8fd5865fe258c336fa0","analyzedAt":"2026-08-01T19:42:02.087Z","schemaVersion":2}