{"record":{"id":"1e13b9876197c4fc","repo":"mui/material-ui","slug":"workspace-name-not-found","errorCode":null,"errorMessage":"Workspace ${name} not found","messagePattern":"Workspace (.+?) not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/releasePack.mts","lineNumber":48,"sourceCode":"  packages[workspace.name] = zipFilePath;\n  return zipFilePath;\n}\n\nasync function run({ packages, outDir, concurrency }: RunOptions) {\n  const allWorkspaces: WorkspaceDefinition[] = await $`pnpm -r ls --depth -1 --json`.then(\n    (result) => JSON.parse(result.stdout),\n  );\n  const workspacesMap = new Map(allWorkspaces.map((workspace) => [workspace.name, workspace]));\n\n  const publicPackages = allWorkspaces\n    .filter((workspace) => !workspace.private)\n    .map((workspace) => workspace.name);\n  const packagesToPack = packages || publicPackages;\n\n  const workspacesToPack = packagesToPack.map((name) => {\n    const workspace = workspacesMap.get(name);\n    if (!workspace) {\n      throw new Error(`Workspace ${name} not found`);\n    }\n    return workspace;\n  });\n\n  const absoluteDestination = path.resolve(outDir);\n\n  const workspacesIterator = workspacesToPack.values();\n  const manifest: Manifest = { packages: {} };\n  const workers = Array.from({ length: concurrency }).map(async () => {\n    for (const workspace of workspacesIterator) {\n      /* eslint-disable no-await-in-loop */\n      console.log(`packing \"${workspace.name}\"`);\n      const zipFilePath = await packWorkspace(workspace, absoluteDestination);\n      const newName = path.join(absoluteDestination, `${workspace.name}.tgz`);\n      await fs.mkdir(path.dirname(newName), { recursive: true });\n      await fs.rename(zipFilePath, newName);\n      const relativeZipFilePath = path.relative(absoluteDestination, newName);\n      manifest.packages[workspace.name] = relativeZipFilePath;","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/mui/material-ui/blob/bdc96df2cb530fcdd60a7a7aabe37f610ce0f0a5/scripts/releasePack.mts#L30-L66","documentation":"Thrown by run() in scripts/releasePack.mts when one of the names passed via --packages (alias -p) is absent from the workspacesMap built from `pnpm -r ls --depth -1 --json`. The script refuses to silently skip an unknown name because that would produce an incomplete manifest.json. When -p is omitted the script defaults to every public workspace, which cannot miss the map, so in practice this only fires for explicitly supplied names.","triggerScenarios":"Caller passes `--packages @mui/lab @mui/nope`; the second name is looked up via workspacesMap.get(' @mui/nope') and returns undefined, throwing. Also fires for a name that exists in a different branch's workspace catalog, or one that was renamed/removed but still referenced by an external pipeline.","commonSituations":"Typo in the package name; passing the unscoped short name instead of the full scoped name (`material` vs `@mui/material`); trailing whitespace or copy-paste artifacts in a `-p` value; running from a branch where the workspace was deleted; passing a name from a private fork that has not been merged.","solutions":["List real workspace names with `pnpm -r ls --depth -1 --json` (or `pnpm list --recursive --depth -1`) and copy the exact `name` field.","Check each `-p` value for typos, missing `@scope/` prefix, or stray whitespace.","Confirm you are on a branch that actually contains the workspace (the list is computed from the current tree).","If you intended to pack a private workspace, note that the auto-default only collects public ones — supply the name explicitly via -p and make sure it matches exactly."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Run before invoking releasePack with --packages.\n// Loads the same source of truth the script uses (pnpm -r ls --json) and\n// rejects any name not present, with the full set of valid names listed.\nimport { execa } from 'execa';\n\nasync function assertWorkspacesExist(requested: string[]) {\n  if (requested.length === 0) return;\n  const { stdout } = await execa`pnpm -r ls --depth -1 --json`;\n  const known = new Set((JSON.parse(stdout) as { name: string }[]).map((w) => w.name));\n  const missing = requested.filter((n) => !known.has(n));\n  if (missing.length > 0) {\n    throw new Error(\n      `Unknown workspace name(s): ${missing.join(', ')}.\\n` +\n      `Valid names: ${[...known].sort().join(', ')}`,\n    );\n  }\n}","typeGuard":"// Narrows a candidate name to one present in a precomputed workspace set.\nfunction makeWorkspaceGuard(known: Set<string>) {\n  return (name: string): name is string => known.has(name);\n}","tryCatchPattern":"// Wrap the run() invocation so the unknown-name error carries the list of\n// valid alternatives instead of just the single missing name.\ntry {\n  await run({ packages, outDir, concurrency });\n} catch (err) {\n  const m = err instanceof Error && err.message.match(/^Workspace (.*) not found$/);\n  if (m) {\n    throw new Error(\n      `Unknown workspace name \"${m[1]}\". Run \\`pnpm -r ls --depth -1 --json\\` to list valid names.`,\n    );\n  }\n  throw err;\n}","preventionTips":["Always source package names from `pnpm -r ls --depth -1 --json` rather than typing them by hand.","Use the fully-scoped name (`@mui/material`, not `material`) — pnpm reports names with their scope.","Pin the script invocation in CI rather than passing names dynamically from a fragile upstream job.","When deleting or renaming a workspace, grep the repo and any adjacent pipelines for stale references."],"tags":["workspace","monorepo","cli","pnpm","argument-validation"],"backgroundTag":null,"analyzedSha":"bdc96df2cb530fcdd60a7a7aabe37f610ce0f0a5","analyzedAt":"2026-08-12T22:59:56.717Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}