prisma/prisma · error · Error

${manifestPath}: not valid JSON (${error instanceof Error ?

Error message

${manifestPath}: not valid JSON (${error instanceof Error ? error.message : String(error)})

What it means

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.

Source

Thrown at skills/extension-author/prisma-next-extension-upgrade/upgrades/0.16-to-0.17/strip-sha256-hash-prefixes.ts:251

    return { path, status: 'already-clean' };
  }
  if (!dryRun) await writeFile(path, after, 'utf-8');
  return { path, status: dryRun ? 'needs-fix' : 'fixed' };
}

async function processSibling(path: string): Promise<Result> {
  const raw = await readFile(path, 'utf-8');
  return emit(path, raw, stripHashPrefixes(raw));
}

async function processPackage(manifestPath: string): Promise<Result[]> {
  const raw = await readFile(manifestPath, 'utf-8');

  let parsed: unknown;
  try {
    parsed = JSON.parse(raw);
  } catch (error) {
    throw new Error(
      `${manifestPath}: not valid JSON (${error instanceof Error ? error.message : String(error)})`,
    );
  }
  if (!isJsonObject(parsed)) {
    return [{ path: manifestPath, status: 'already-clean' }]; // not a manifest object
  }

  const packageDir = dirname(manifestPath);

  // A complete on-disk migration package pairs `migration.json` with a sibling
  // `ops.json` (the operations the hash is computed over); without it we cannot
  // recompute the hash, so this is not a package we should touch.
  const opsPath = join(packageDir, 'ops.json');
  let opsRaw: string;
  try {
    opsRaw = await readFile(opsPath, 'utf-8');
  } catch {
    return [{ path: manifestPath, status: 'skipped-no-ops' }];

View on GitHub (pinned to 1243cdffbe)

Solutions

  1. 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.
  2. If the corruption is from a git merge conflict, resolve the conflict markers then re-run the codemod (it is idempotent).
  3. 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.
  4. Validate the file with a JSON linter (`pnpm exec tsx -e "JSON.parse(require('fs').readFileSync('<path>','utf8'))"`) before re-running.

Example fix

// before — migrations/0001_init/migration.json
{
  "from": "sha256:8ee1e7ce...",
  "to": "sha256:059f3f35...",
  "providedInvariants": [],  // <- trailing comma / comment breaks JSON.parse
}

// after
{
  "from": "sha256:8ee1e7ce...",
  "to": "sha256:059f3f35...",
  "providedInvariants": []
}
Defensive patterns

Strategy: try-catch

Validate before calling

import { readFile } from 'node:fs/promises';

// Pre-scan every migration.json / package.json before invoking the upgrade.
async function assertManifestsAreValidJson(paths: string[]): Promise<void> {
  for (const manifestPath of paths) {
    const raw = await readFile(manifestPath, 'utf-8');
    try { JSON.parse(raw); }
    catch (error) {
      const msg = error instanceof Error ? error.message : String(error);
      throw new Error(`Refusing to run upgrade: ${manifestPath} is not valid JSON (${msg})`);
    }
  }
}

Try / catch

try {
  await runUpgradeScripts(projectRoot);
} catch (error) {
  if (error instanceof Error && error.message.includes(': not valid JSON (')) {
    const offending = error.message.split(':')[0];
    console.error(`Upgrade aborted: fix or regenerate ${offending}, then re-run.`);
    process.exit(1);
  }
  throw error;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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`.

Related errors


AI-assisted analysis of prisma/prisma@1243cdffbe (2026-08-01). Data as JSON: /data/errors/970bf1dcbbce1093.json. Report an issue: GitHub.