{"record":{"id":"c06a4429cfcce9b7","repo":"vercel/turborepo","slug":"new-workspace-root-detected-unexpected-pnpm-work","errorCode":null,"errorMessage":"New workspace root detected - unexpected pnpm-workspace.yaml","messagePattern":"New workspace root detected - unexpected pnpm-workspace\\.yaml","errorType":"console","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/turbo-gen/src/generators/copy.ts","lineNumber":51,"sourceCode":"      examplePath: opts.examplePath\n    });\n\n    try {\n      if (fs.existsSync(newPackageJsonPath)) {\n        const packageJson = (await fs.readJSON(\n          newPackageJsonPath\n        )) as PackageJson;\n        if (packageJson.workspaces) {\n          throw new Error(\n            \"New workspace root detected - unexpected 'workspaces' field in package.json\"\n          );\n        }\n      } else {\n        throw new Error(\"New workspace is missing a package.json file\");\n      }\n\n      if (fs.existsSync(path.join(location.absolute, \"pnpm-workspace.yaml\"))) {\n        throw new Error(\n          \"New workspace root detected - unexpected pnpm-workspace.yaml\"\n        );\n      }\n    } catch (err) {\n      let message = \"UNKNOWN_ERROR\";\n      if (err instanceof Error) {\n        message = err.message;\n      }\n      logger.error(message);\n\n      // rollback changes\n      await fs.rm(location.absolute, { recursive: true, force: true });\n      return;\n    }\n  } else if (source) {\n    const filterFunc: CopyFilterAsync = async (src) =>\n      !src.includes(\"node_modules\");\n","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/vercel/turborepo/blob/9f94a7d215b3881942527dd526afa3fc650869d5/packages/turbo-gen/src/generators/copy.ts#L33-L69","documentation":"The other `turbo gen --copy` post-copy guard: a pnpm-workspace.yaml at the copied root marks the source as a pnpm monorepo root, which cannot be nested inside your monorepo as a single workspace. The check runs after the package.json checks; on failure the copy is logged and rolled back (directory recursively removed).","triggerScenarios":"Passing --copy a directory that contains a pnpm-workspace.yaml file at its root — i.e. the root of a pnpm-based monorepo rather than one of its workspace packages.","commonSituations":"Absorbing a pnpm-managed repository by copying its root; a leftover pnpm-workspace.yaml in a repo that no longer uses pnpm workspaces.","solutions":["Copy the individual workspace package from the pnpm monorepo (the sub-directory with its own package.json and no pnpm-workspace.yaml)","If the file is a leftover from an abandoned pnpm setup in a single-package repo, delete pnpm-workspace.yaml from the source and re-run","For whole-monorepo adoption, migrate each package separately or do a manual move plus workspace-glob registration"],"exampleFix":"# before\nturbo gen --copy ~/src/pnpm-monorepo      # root contains pnpm-workspace.yaml\n# after\nturbo gen --copy ~/src/pnpm-monorepo/packages/ui","handlingStrategy":"validation","validationCode":"import fs from 'node:fs';\nimport path from 'node:path';\n\nfunction isPnpmMonorepoRoot(dir: string): boolean {\n  return fs.existsSync(path.join(dir, 'pnpm-workspace.yaml'));\n}\n// reject isPnpmMonorepoRoot(source) before turbo gen --copy <source>","typeGuard":"function isWorkspaceRootMarker(dir: string): boolean {\n  return fs.existsSync(path.join(dir, 'pnpm-workspace.yaml'));\n}","tryCatchPattern":null,"preventionTips":["Copy individual workspace packages out of pnpm monorepos, never their roots","Delete stale pnpm-workspace.yaml files from single-package repos before copying them in","Note the guard order: package.json checks run first, so fix any earlier reported errors before this one"],"tags":["turbo-gen","workspace","pnpm","monorepo","copy"],"backgroundTag":"workspace-config-conflict","analyzedSha":"9f94a7d215b3881942527dd526afa3fc650869d5","analyzedAt":"2026-08-16T19:47:29.531Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}