vercel/turborepo · error · ConvertError

package_manager-unexpected

package_manager-unexpected

Error message

Not a yarn project

What it means

Thrown by the yarn manager handler's read() in turbo-workspaces when yarn's detect() returns false. Detection means: yarn.lock exists OR the packageManager/devEngines.packageManager field declares yarn (both classic and berry count - the handler does not distinguish them). ConvertError type "package_manager-unexpected".

Source

Thrown at packages/turbo-workspaces/src/managers/yarn.ts:58

 */
// eslint-disable-next-line @typescript-eslint/require-await -- must match the detect type signature
async function detect(args: DetectArgs): Promise<boolean> {
  const lockFile = path.join(args.workspaceRoot, PACKAGE_MANAGER_DETAILS.lock);
  const packageManager = getWorkspacePackageManager({
    workspaceRoot: args.workspaceRoot
  });
  return (
    fs.existsSync(lockFile) || packageManager === PACKAGE_MANAGER_DETAILS.name
  );
}

/**
  Read workspace data from yarn workspaces into generic format
*/
async function read(args: ReadArgs): Promise<Project> {
  const isYarn = await detect(args);
  if (!isYarn) {
    throw new ConvertError("Not a yarn project", {
      type: "package_manager-unexpected"
    });
  }

  const packageJson = getPackageJson(args);
  const { name, description } = getWorkspaceInfo(args);
  const workspaceGlobs = parseWorkspacePackages({
    workspaces: packageJson.workspaces
  });
  return {
    name,
    description,
    packageManager: PACKAGE_MANAGER_DETAILS.name,
    paths: expandPaths({
      root: args.workspaceRoot,
      lockFile: PACKAGE_MANAGER_DETAILS.lock
    }),
    workspaceData: {

View on GitHub (pinned to 9f94a7d215)

Solutions

  1. Ensure yarn.lock exists at the root (run `yarn install`) or add "packageManager": "yarn@<version>" (e.g. yarn@4.1.0 or yarn@1.22.x) / devEngines.packageManager declaration to package.json
  2. Use getWorkspaceDetails({ root }) instead of MANAGERS.yarn.read so detection picks the manager whose artifacts actually exist
  3. Commit yarn.lock (or at least keep it present during migration) so detection has a stable marker
  4. Avoid mutating the repo (clean/checkout) while a conversion is running

Example fix

// before
const project = await MANAGERS.yarn.read({ workspaceRoot: root });

// after
if (await MANAGERS.yarn.detect({ workspaceRoot: root })) {
  const project = await MANAGERS.yarn.read({ workspaceRoot: root });
}
Defensive patterns

Strategy: validation

Validate before calling

import { MANAGERS } from "turbo-workspaces";
import { existsSync } from "node:fs";
import path from "node:path";

if (!existsSync(path.join(root, "yarn.lock"))) {
  throw new Error(`${root} has no yarn.lock - not a yarn project`);
}
const project = await MANAGERS.yarn.read({ workspaceRoot: root });

Type guard

import { ConvertError } from "turbo-workspaces";

function isPackageManagerUnexpected(err: unknown): err is ConvertError {
  return err instanceof ConvertError && err.type === "package_manager-unexpected";
}

Try / catch

try {
  const project = await MANAGERS.yarn.read({ workspaceRoot: root });
} catch (err) {
  if (err instanceof ConvertError && err.type === "package_manager-unexpected") {
    project = await getWorkspaceDetails({ root });
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling MANAGERS.yarn.read({ workspaceRoot }) directly when there is no yarn.lock and no yarn declaration; via getWorkspaceDetails()/convert() only when yarn.lock or the declaration vanishes between detect() and read() (concurrent git operation, clean script, editor save).

Common situations: Yarn Berry projects that do not commit yarn.lock or use a non-standard install; the packageManager field stripped by a merge conflict resolution or removed when someone disabled corepack; wrong workspaceRoot passed (sub-package directory instead of the repo root that owns yarn.lock); assuming a yarn global install means the project is yarn-managed.

Related errors


AI-assisted analysis of vercel/turborepo@9f94a7d215 (2026-08-16). Data as JSON: /api/errors/722034258ecfe5f8. Report an issue: GitHub.