mui/material-ui · error · Error

Failed to install dependencies

Error message

Failed to install dependencies

What it means

Thrown from the `exit` event handler of the spawned `pnpm install --no-frozen-lockfile` when that process exits with a non-zero code. By the time this runs, the script has already rewritten package.json with the new React resolutions, so the install itself is what failed. Note the throw is inside an async event handler, so it surfaces as an unhandled rejection rather than being caught by main().catch() — the surrounding promise has already settled.

Source

Thrown at scripts/useReactVersion.mjs:106

        throw new Error(
          `Version ${majorVersion} does not have version defined for the ${packageName}`,
        );
      }
      packageJson.resolutions[packageName] = additionalVersionsMappings[majorVersion][packageName];
    });
  }

  // add newline for clean diff
  fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}${os.EOL}`);

  console.log('Installing dependencies...');
  const pnpmInstall = childProcess.spawn('pnpm', ['install', '--no-frozen-lockfile'], {
    shell: true,
    stdio: ['inherit', 'inherit', 'inherit'],
  });
  pnpmInstall.on('exit', (exitCode) => {
    if (exitCode !== 0) {
      throw new Error('Failed to install dependencies');
    }
  });
}

const [version = process.env.REACT_VERSION] = process.argv.slice(2);
main(version).catch((error) => {
  console.error(error);
  process.exit(1);
});

View on GitHub (pinned to bdc96df2cb)

Solutions

  1. Reproduce manually: `pnpm install --no-frozen-lockfile` in the repo root and read the actual error.
  2. Inspect `package.json` `resolutions` — if a value looks wrong, fix the version/tag passed to the script and re-run.
  3. Verify `pnpm` is installed and on PATH (`which pnpm`, `pnpm --version`) and that the registry is reachable (`npm ping`).
  4. If the lockfile is unsalvageable, regenerate it deliberately: remove `pnpm-lock.yaml` and re-run install.

Example fix

// before
const pnpmInstall = childProcess.spawn('pnpm', ['install', '--no-frozen-lockfile'], {
  shell: true,
  stdio: ['inherit', 'inherit', 'inherit'],
});
pnpmInstall.on('exit', (exitCode) => {
  if (exitCode !== 0) {
    throw new Error('Failed to install dependencies');
  }
});

// after
const pnpmInstall = childProcess.spawn('pnpm', ['install', '--no-frozen-lockfile'], {
  shell: true,
  stdio: ['inherit', 'inherit', 'inherit'],
});
await new Promise<void>((resolve, reject) => {
  pnpmInstall.on('exit', (exitCode) => {
    if (exitCode === 0) resolve();
    else reject(new Error(`Failed to install dependencies (pnpm exit ${exitCode})`));
  });
  pnpmInstall.on('error', reject);
});
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight before invoking useReactVersion: confirm pnpm is on PATH and
// the registry is reachable, so install is less likely to fail.
import { exec } from 'node:child_process';
import { promisify } from 'node:util';
const execAsync = promisify(exec);

async function assertInstallReady() {
  try {
    await execAsync('pnpm --version');
  } catch {
    throw new Error('pnpm not found on PATH; install it before running useReactVersion.');
  }
  try {
    await execAsync('npm ping');
  } catch {
    throw new Error('npm registry unreachable; check network/proxy/registry config.');
  }
}

Type guard

// Narrows an unknown to a NodeJS spawn exit that the install handler can
// inspect deterministically.
function isNonZeroExit(
  code: number | string | null,
): code is number {
  return typeof code === 'number' && code !== 0;
}

Try / catch

// The current script throws from an async exit handler, which becomes an
// unhandled rejection. Promisify the spawn so the failure flows through
// main().catch and surfaces the real exit code.
await new Promise<void>((resolve, reject) => {
  const child = childProcess.spawn('pnpm', ['install', '--no-frozen-lockfile'], {
    shell: true,
    stdio: 'inherit',
  });
  child.on('exit', (code) =>
    code === 0 ? resolve() : reject(new Error(`pnpm install failed (exit ${code})`)),
  );
  child.on('error', reject);
});

Prevention

When it happens

Trigger: pnpm install returns non-zero: peer-dependency or resolution conflict; network or registry failure; invalid version string written into package.json.resolutions by the earlier steps; lockfile incompatible with the new resolutions; or `pnpm` not on PATH (in which case the spawn itself errors). Also fires when the resolutions point at versions that do not exist on the registry.

Common situations: CI with an empty or partially-warmed npm cache; corporate proxy blocking the registry; a typo'd version or tag passed to the script producing a bad resolution; switching React versions mid-branch leaving a dirty lockfile; runner image without pnpm installed.

Related errors


AI-assisted analysis of mui/material-ui@bdc96df2cb (2026-08-12). Data as JSON: /api/errors/e9d9554943354bce. Report an issue: GitHub.