{"record":{"id":"69617a5fdf66b947","repo":"mui/material-ui","slug":"expected-version-string-but-got-version","errorCode":null,"errorMessage":"expected version: string but got '${version}'","messagePattern":"expected version: string but got '(.+?)'","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"scripts/useReactVersion.mjs","lineNumber":31,"sourceCode":"import path from 'path';\nimport { promisify } from 'util';\n\nconst exec = promisify(childProcess.exec);\n\n// packages published from the react monorepo using the same version\nconst reactPackageNames = ['react', 'react-dom', 'react-is', 'scheduler'];\nconst devDependenciesPackageNames = ['@testing-library/react'];\n\n// if we need to support more versions we will need to add new mapping here\nconst additionalVersionsMappings = {\n  17: {\n    '@testing-library/react': '^12.1.0',\n  },\n};\n\nasync function main(version) {\n  if (typeof version !== 'string') {\n    throw new TypeError(`expected version: string but got '${version}'`);\n  }\n\n  if (version === 'stable') {\n    console.log('Nothing to do with stable');\n    return;\n  }\n\n  const packageJsonPath = path.resolve(process.cwd(), 'package.json');\n  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, { encoding: 'utf8' }));\n\n  // the version is something in format: \"17.0.0\"\n  let majorVersion = null;\n\n  if (version.startsWith('^') || version.startsWith('~') || !Number.isNaN(version.charAt(0))) {\n    majorVersion = version.replace('^', '').replace('~', '').split('.')[0];\n  }\n\n  await Promise.all(","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/mui/material-ui/blob/bdc96df2cb530fcdd60a7a7aabe37f610ce0f0a5/scripts/useReactVersion.mjs#L13-L49","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"// Put this at the top of a CI wrapper before invoking the script.\nconst v = process.argv[2] ?? process.env.REACT_VERSION;\nif (typeof v !== 'string' || v.length === 0) {\n  console.error('Missing React version. Pass it as an argument or set REACT_VERSION.');\n  process.exit(2);\n}\n// Now safe to delegate:\n// spawn('node', ['scripts/useReactVersion.mjs', v], { stdio: 'inherit' });","typeGuard":"// Mirrors the exact check the script performs at useReactVersion.mjs:30.\nfunction isReactVersionArg(value: unknown): value is string {\n  return typeof value === 'string' && value.length > 0;\n}\n\n// Usage:\n//   const v = process.argv[2] ?? process.env.REACT_VERSION;\n//   if (!isReactVersionArg(v)) { /* bail with a helpful message */ }","tryCatchPattern":"// The script already has a top-level `.catch` that prints and exits 1.\n// In a wrapper, distinguish the TypeError (bad input) from runtime errors:\ntry {\n  await main(version);\n} catch (err) {\n  if (err instanceof TypeError && /expected version: string/.test(err.message)) {\n    console.error('usage: useReactVersion.mjs <stable|next|experimental|<version>|<range>>');\n    process.exit(2);\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["cli","env","type-validation","react","argv"],"backgroundTag":null,"analyzedSha":"bdc96df2cb530fcdd60a7a7aabe37f610ce0f0a5","analyzedAt":"2026-08-12T22:59:56.717Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}