remix-run/react-router · error · Error

package.json are invalid

Error message

package.json ${pkgKey} are invalid

What it means

While normalizing the template's package.json, updatePackageJSON() iterates dependencies and devDependencies; if one of those fields is present but not a plain JSON object (isValidJsonObject fails — e.g. an array, string, or number), it cannot rewrite react-router versions and aborts. A missing field is fine; a malformed one is not.

Solutions

  1. Make dependencies/devDependencies objects mapping package names to version ranges
  2. Remove the invalid field entirely if the template has no dependencies
  3. Fix the template source and re-run the scaffold

Example fix

// before: template package.json
{ "name": "tpl", "dependencies": ["react-router"] }

// after
{ "name": "tpl", "dependencies": { "react-router": "*", "react": "^19.0.0", "react-dom": "^19.0.0" } }
Defensive patterns

Strategy: validation

Validate before calling

import fs from "node:fs";

function isValidJsonObject(v: unknown): v is Record<string, unknown> {
  return typeof v === "object" && v !== null && !Array.isArray(v);
}

function validateTemplateManifest(pkgPath: string): void {
  const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
  for (const key of ["dependencies", "devDependencies"] as const) {
    if (pkg[key] !== undefined && !isValidJsonObject(pkg[key])) {
      throw new Error(`package.json ${key} must be an object of name -> version range`);
    }
  }
}

validateTemplateManifest("./template/package.json");

Type guard

function isValidJsonObject(v: unknown): v is Record<string, unknown> {
  return typeof v === "object" && v !== null && !Array.isArray(v);
}

Try / catch

try {
  await createReactRouter(args);
} catch (e) {
  const msg = e instanceof Error ? e.message : String(e);
  if (/package\.json (dependencies|devDependencies) are invalid/.test(msg)) {
    console.error("Fix the template manifest: dependency fields must be objects.");
    process.exit(1);
  }
  throw e;
}

Prevention

When it happens

Trigger: Template package.json containing "dependencies": [], "devDependencies": "latest", or similar non-object values; generated templates that emit strings instead of maps.

Common situations: Hand-edited or machine-generated templates with malformed manifest fields.

Related errors


AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18). Data as JSON: /api/errors/44e4f8383cbd68b6. Report an issue: GitHub.

Appendix: source

Thrown at packages/create-react-router/index.ts:695

    error(
      "Oh no!",
      "The provided template must be a React Router project with a `package.json` " +
        `file, but that file is invalid.`,
    );
    throw err;
  }

  for (let pkgKey of ["dependencies", "devDependencies"] as const) {
    let dependencies = packageJSON[pkgKey];
    if (!dependencies) continue;

    if (!isValidJsonObject(dependencies)) {
      error(
        "Oh no!",
        "The provided template must be a React Router project with a `package.json` " +
          `file, but its ${pkgKey} value is invalid.`,
      );
      throw new Error(`package.json ${pkgKey} are invalid`);
    }

    for (let dependency in dependencies) {
      let version = dependencies[dependency];
      if (
        (dependency.startsWith("@react-router/") ||
          dependency === "react-router") &&
        version === "*"
      ) {
        dependencies[dependency] = semver.prerelease(ctx.reactRouterVersion)
          ? // Templates created from prereleases should pin to a specific version
            ctx.reactRouterVersion
          : "^" + ctx.reactRouterVersion;
      }
    }
  }

  packageJSON.name = ctx.projectName;

View on GitHub (pinned to 6beaca3952)