{"record":{"id":"cb535421cca59ac5","repo":"pnpm/pnpm","slug":"failed-to-clean-up-replaced-global-installs","errorCode":null,"errorMessage":"Failed to clean up replaced global installs","messagePattern":"Failed to clean up replaced global installs","errorType":"exception","errorClass":"AggregateError","httpStatus":null,"severity":"warning","filePath":"pnpm11/global/commands/src/globalActivation.ts","lineNumber":95,"sourceCode":"    // Activation is already committed, so a leftover backup directory\n    // must not fail the command — but it points at a filesystem problem\n    // worth surfacing.\n    globalWarn(`Failed to remove the global bin backup directory at ${prepared.backupDir}: ${getErrorMessage(err)}`)\n  }\n  return prepared.actualBinNames\n}\n\nexport async function cleanupReplacedGlobalInstalls (\n  opts: CleanupReplacedGlobalInstallsOptions\n): Promise<void> {\n  const errors: unknown[] = []\n  for (const group of opts.groups) {\n    // eslint-disable-next-line no-await-in-loop -- Cleanup mutations must settle before the next group starts.\n    errors.push(...await cleanupReplacedGlobalInstall(opts, group))\n  }\n  if (errors.length === 1) throw errors[0]\n  if (errors.length > 1) {\n    throw new AggregateError(errors, 'Failed to clean up replaced global installs')\n  }\n}\n\n// Activation already succeeded when this runs, so every removal is\n// attempted even after one fails; the failures are aggregated instead of\n// aborting the remaining cleanup.\nasync function cleanupReplacedGlobalInstall (\n  opts: CleanupReplacedGlobalInstallsOptions,\n  group: GlobalPackageInfo\n): Promise<unknown[]> {\n  const errors: unknown[] = []\n  let binNames: string[]\n  try {\n    binNames = await getInstalledBinNames(group)\n  } catch (err) {\n    // The install directory is the only record of which bins the group\n    // owns, so removing it now would strand them on PATH forever. Leave\n    // the group intact for a later run to clean up.","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/pnpm/pnpm/blob/5b11d3a15b9022a2109cb18ed96a5d652630371f/pnpm11/global/commands/src/globalActivation.ts#L77-L113","documentation":"cleanupReplacedGlobalInstalls runs after activation already succeeded, removing installs that this activation replaced. Every group's removal is attempted even after failures; with exactly one failure that error is rethrown as-is, and with several the errors are wrapped in an AggregateError ('Failed to clean up replaced global installs'). The new install is live — only old directories or bins remain on disk.","triggerScenarios":"Post-activation removal of a replaced install directory or old bin fails: EBUSY/EPERM from locked files on Windows, read-only files, a terminal whose cwd is inside the removed directory, or a process holding an old shim open.","commonSituations":"Windows file locks on old shims during global update; editors or shells sitting inside the old install dir; leftovers from previous installs with unusual permissions.","solutions":["Treat as non-fatal if the command you needed works: verify with `pnpm ls -g` and by running the binaries","Close processes and terminals holding the old install paths, then re-run the global install so cleanup retries","Delete the leftover replaced-install directories under the global package dir manually"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isCleanupAggregate (err: unknown): err is AggregateError {\n  return util.types.isNativeError(err) && Array.isArray((err as AggregateError).errors)\n}","tryCatchPattern":"try {\n  await activateAndCleanup(opts)\n} catch (err) {\n  if (isCleanupAggregate(err) && err.message === 'Failed to clean up replaced global installs') {\n    // activation already succeeded: log err.errors and continue — verify bins run, clean leftovers later\n    for (const e of err.errors) log.warn('cleanup failure:', e)\n    return\n  }\n  throw err\n}","preventionTips":["Close shells and processes using global bins before updating global packages","Periodically prune the global dir of orphaned old installs","Treat cleanup AggregateErrors as warnings in automation, not install failures"],"tags":["global","cleanup","aggregate-error","filesystem"],"backgroundTag":null,"analyzedSha":"5b11d3a15b9022a2109cb18ed96a5d652630371f","analyzedAt":"2026-08-16T13:18:59.198Z","schemaVersion":2},"datasetVersion":"2026-08-16T18:17:16.020Z"}