{"record":{"id":"0917844b8647bf84","repo":"vercel/turborepo","slug":"error-removing-node-modules-091784","errorCode":"error_removing_node_modules","errorMessage":"Failed to remove node_modules","messagePattern":"Failed to remove node_modules","errorType":"exception","errorClass":"ConvertError","httpStatus":null,"severity":"error","filePath":"packages/turbo-workspaces/src/managers/npm.ts","lineNumber":205,"sourceCode":"  });\n\n  if (!options?.dry) {\n    fs.writeJSONSync(project.paths.packageJson, packageJson, { spaces: 2 });\n\n    // collect all workspace node_modules directories\n    const allModulesDirs = [\n      project.paths.nodeModules,\n      ...project.workspaceData.workspaces.map((w) => w.paths.nodeModules)\n    ];\n    try {\n      logger.subStep(`removing \"node_modules\"`);\n      await Promise.all(\n        allModulesDirs.map((dir) =>\n          fs.rm(dir, { recursive: true, force: true })\n        )\n      );\n    } catch (err) {\n      throw new ConvertError(\"Failed to remove node_modules\", {\n        type: \"error_removing_node_modules\"\n      });\n    }\n  }\n}\n\n/**\n * Clean is called post install, and is used to clean up any files\n * from this package manager that were needed for install,\n * but not required after migration\n */\n// eslint-disable-next-line @typescript-eslint/require-await -- must match the clean type signature\nasync function clean(args: CleanArgs): Promise<void> {\n  const { project, logger, options } = args;\n\n  logger.subStep(\n    `removing ${path.relative(project.paths.root, project.paths.lockfile)}`\n  );","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/vercel/turborepo/blob/f9245100cf0d31d96628804ead485f6bf226e55a/packages/turbo-workspaces/src/managers/npm.ts#L187-L223","documentation":"Identical cleanup step to bun's, in the npm conversion path: fs.rm(recursive, force) over root and workspace node_modules directories; any rejection is rethrown as ConvertError type error_removing_node_modules. The conversion aborts before install because stale node_modules from the old manager would corrupt the new one.","triggerScenarios":"Converting to/from npm while node_modules is locked or undeletable: EBUSY/EPERM on Windows (files open in another process), EACCES from wrong ownership in containers, ENOTEMPTY from concurrent modification, or long-path failures on Windows without long path support enabled.","commonSituations":"Windows with VS Code/dev servers open, antivirus scanners holding handles, CI volumes with odd permissions, path-length overflow with deeply nested deps when long paths are disabled.","solutions":["Close all processes touching the repo (editors, watch mode, terminals cd'd into it) and rerun","Retry after a short delay - Windows EBUSY is often transient once handles release","Remove manually then rerun conversion: npx rimraf node_modules plus each workspace's node_modules","On Windows enable long path support or move the repo shallower if path length is the cause","In CI, ensure no cached node_modules is mounted read-only"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"import { accessSync, constants } from \"node:fs\";\n\nfunction nodeModulesRemovable(paths: string[]): boolean {\n  return paths.every((p) => {\n    try { accessSync(p, constants.W_OK); return true; } catch { return false; }\n  });\n}\n// pre-validate project.paths.nodeModules + workspace node_modules before convert","typeGuard":null,"tryCatchPattern":"try {\n  await convert({ project, convertTo: npmDetails, logger });\n} catch (err) {\n  if (err instanceof ConvertError && err.type === \"error_removing_node_modules\") {\n    // EBUSY/EPERM: kill processes locking the tree, npx rimraf node_modules, retry once\n  }\n  throw err;\n}","preventionTips":["Shut down watch mode and editors touching node_modules before converting","Enable Windows long-path support or keep repos near the drive root","Retry once after a delay - Windows handle release is often delayed"],"tags":["filesystem","npm","node-modules","windows","convert"],"backgroundTag":"file-remove-failed","analyzedSha":"f9245100cf0d31d96628804ead485f6bf226e55a","analyzedAt":"2026-08-17T10:46:15.696Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}