mui/material-ui · error · TypeError
expected version: string but got '${version}'
Error message
expected version: string but got '${version}' What it means
TypeError thrown at the top of main(version) in scripts/useReactVersion.mjs when typeof version !== 'string'. The version argument defaults to process.env.REACT_VERSION when no positional argv is supplied, so if both are unset the value is undefined and the guard rejects it before any file is touched. It is a TypeError (rather than Error) because the call contract was violated — main expects a string.
Source
Thrown at scripts/useReactVersion.mjs:31
import path from 'path';
import { promisify } from 'util';
const exec = promisify(childProcess.exec);
// packages published from the react monorepo using the same version
const reactPackageNames = ['react', 'react-dom', 'react-is', 'scheduler'];
const devDependenciesPackageNames = ['@testing-library/react'];
// if we need to support more versions we will need to add new mapping here
const additionalVersionsMappings = {
17: {
'@testing-library/react': '^12.1.0',
},
};
async function main(version) {
if (typeof version !== 'string') {
throw new TypeError(`expected version: string but got '${version}'`);
}
if (version === 'stable') {
console.log('Nothing to do with stable');
return;
}
const packageJsonPath = path.resolve(process.cwd(), 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, { encoding: 'utf8' }));
// the version is something in format: "17.0.0"
let majorVersion = null;
if (version.startsWith('^') || version.startsWith('~') || !Number.isNaN(version.charAt(0))) {
majorVersion = version.replace('^', '').replace('~', '').split('.')[0];
}
await Promise.all(View on GitHub (pinned to bdc96df2cb)
Solutions
- Pass a positional argument: `node scripts/useReactVersion.mjs next` (or `stable`, `17.0.0`, `^18`, etc.).
- Or export the env var first: `REACT_VERSION=next node scripts/useReactVersion.mjs`.
- In CI, make sure REACT_VERSION is set on every leg of the matrix before the script step (use `env: REACT_VERSION: ${{ matrix.react }}` on the step).
Defensive patterns
Strategy: type-guard
Validate before calling
// Put this at the top of a CI wrapper before invoking the script.
const v = process.argv[2] ?? process.env.REACT_VERSION;
if (typeof v !== 'string' || v.length === 0) {
console.error('Missing React version. Pass it as an argument or set REACT_VERSION.');
process.exit(2);
}
// Now safe to delegate:
// spawn('node', ['scripts/useReactVersion.mjs', v], { stdio: 'inherit' }); Type guard
// Mirrors the exact check the script performs at useReactVersion.mjs:30.
function isReactVersionArg(value: unknown): value is string {
return typeof value === 'string' && value.length > 0;
}
// Usage:
// const v = process.argv[2] ?? process.env.REACT_VERSION;
// if (!isReactVersionArg(v)) { /* bail with a helpful message */ } Try / catch
// The script already has a top-level `.catch` that prints and exits 1.
// In a wrapper, distinguish the TypeError (bad input) from runtime errors:
try {
await main(version);
} catch (err) {
if (err instanceof TypeError && /expected version: string/.test(err.message)) {
console.error('usage: useReactVersion.mjs <stable|next|experimental|<version>|<range>>');
process.exit(2);
}
throw err;
} Prevention
- Always pass the version positionally in CI: `node scripts/useReactVersion.mjs ${{ matrix.react }}`.
- If you prefer env vars, set REACT_VERSION on every matrix leg, not just some.
- Document the accepted forms (stable | next | experimental | concrete version | range) next to the script invocation in your pipeline.
- Treat a missing argument as a usage error (exit 2) in wrappers so it is not confused with a script failure.
When it happens
Trigger: Running `node scripts/useReactVersion.mjs` with no positional argument while REACT_VERSION is not exported; a wrapper script that calls main(undefined) or main(null); a CI matrix leg that forgot to inject the env var on one axis.
Common situations: CI job that sets REACT_VERSION conditionally per matrix leg; renamed env var (e.g. REACT_VERSION vs REACT_RELEASE); copy-pasted invocation that drops the positional arg; running the script through a shell wrapper that swallowed the argument.
Related errors
- Transform '${transform}' not found. Check out ${path.resolve
- No TabContext provided
- No TabContext provided
- MUI: MenuListContext is missing. MenuItems must be placed wi
- MUI: RovingTabIndexContext is missing. Roving tab index item
AI-assisted analysis of mui/material-ui@bdc96df2cb (2026-08-12).
Data as JSON: /api/errors/69617a5fdf66b947.
Report an issue: GitHub.