{"record":{"id":"fbb9031dcbd6b24c","repo":"shadcn-ui/ui","slug":"could-not-remove-removablepackages-join","errorCode":null,"errorMessage":"Could not remove ${removablePackages.join(\n          \", \"\n        )}. Remove them manually after reviewing the migration.","messagePattern":"Could not remove (.+?)\\. Remove them manually after reviewing the migration\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/shadcn/src/migrations/cn/index.ts","lineNumber":108,"sourceCode":"    `Migrated ${changedFiles.length} file${changedFiles.length === 1 ? \"\" : \"s\"}.`\n  )\n\n  const retainedPackages = new Set(\n    results.flatMap(({ result }) => result.remainingPackages)\n  )\n  const removablePackages = options.path\n    ? []\n    : OLD_PACKAGES.filter(\n        (packageName) =>\n          migratedPackages.has(packageName) &&\n          !retainedPackages.has(packageName)\n      )\n\n  if (removablePackages.length) {\n    try {\n      await removeDependencies(options.cwd, removablePackages)\n    } catch {\n      logger.warn(\n        `Could not remove ${removablePackages.join(\n          \", \"\n        )}. Remove them manually after reviewing the migration.`\n      )\n    }\n  }\n\n  if (options.path) {\n    logger.info(\n      \"Kept clsx, tailwind-merge and cnfast dependencies because this was a scoped migration.\"\n    )\n  }\n\n  printUnsupportedIssues(unsupported, options.cwd)\n}\n\nfunction assertTailwindCompatibility(\n  cwd: string,","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/shadcn-ui/ui/blob/5c7072da672b0048bc6771e3204063a2537df91a/packages/shadcn/src/migrations/cn/index.ts#L90-L126","documentation":"After a successful migration, migrateCn tries to uninstall the now-unused old packages (clsx, tailwind-merge, cnfast) via removeDependencies. That call runs a package-manager command which can fail; the CLI catches the failure and only logs a warning telling you to remove the packages manually — the migration itself is not rolled back or marked failed.","triggerScenarios":"removeDependencies throwing for any reason (package manager not installed, lockfile conflicts, no network, read-only node_modules, unsupported package manager) while OLD_PACKAGES members are eligible for removal in an unscoped (no --path) migration.","commonSituations":"Offline CI or air-gapped machines where the uninstall command cannot resolve the lockfile; pnpm/yarn/npm not on PATH in minimal containers; permission problems in globally-managed or Docker-owned directories.","solutions":["Manually uninstall the listed packages: `npm uninstall clsx tailwind-merge cnfast` (or your package manager's equivalent).","Fix the underlying package-manager issue (install it, check network, fix permissions) and rerun the removal.","Verify package.json and the lockfile afterwards to confirm the packages are gone and committed.","Check node_modules write permissions if the failure was EACCES/EBUSY."],"exampleFix":"// manual cleanup after the warning\n// before (package.json)\n\"clsx\": \"^2.1.0\",\n\"tailwind-merge\": \"^3.0.0\"\n// after: run `npm uninstall clsx tailwind-merge`\n\"cn\": \"latest\"","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await migrateCn({ cwd: process.cwd(), yes: true })\n} catch {\n  // migration failures throw; dependency-removal failures only warn\n} finally {\n  // verify cleanup\n  const pkg = JSON.parse(readFileSync('package.json', 'utf8'))\n  const stale = ['clsx', 'tailwind-merge', 'cnfast'].filter(p => pkg.dependencies?.[p])\n  if (stale.length) console.warn(`Remove manually: npm uninstall ${stale.join(' ')}`)\n}","preventionTips":["Ensure the package manager (npm/pnpm/yarn) is installed and on PATH before migrating.","Run migrations with network access so lockfile updates succeed.","Check write permissions on package.json/node_modules in containers.","After migrating, grep package.json for the old packages and uninstall leftovers."],"tags":["dependencies","package-manager","cleanup"],"backgroundTag":"file-write-failed","analyzedSha":"5c7072da672b0048bc6771e3204063a2537df91a","analyzedAt":"2026-09-07T00:08:47.579Z","contentChangedAt":"2026-09-07T00:08:47.579Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}