vercel/turborepo · error · ConvertError

package_manager-unable_to_detect

package_manager-unable_to_detect

Error message

Could not determine package manager. Add `devEngines.packageManager` or legacy `packageManager` to `package.json`, or ensure a lockfile is present.

What it means

After confirming the directory exists, getWorkspaceDetails() iterates the MANAGERS map (npm, pnpm, yarn, bun, nub, aube, ...) running each detect() — lockfile presence and/or a declared package manager field. If none claims the workspace it throws ConvertError type package_manager-unable_to_detect with remediation hints in the message.

Source

Thrown at packages/turbo-workspaces/src/get-workspace-details.ts:30

    directory: root
  });
  if (!exists) {
    throw new ConvertError(
      `Could not find directory at ${workspaceRoot}. Ensure the directory exists.`,
      {
        type: "invalid_directory"
      }
    );
  }

  for (const { detect, read } of Object.values(MANAGERS)) {
    // eslint-disable-next-line no-await-in-loop -- we want to run serially and bail on the first success
    if (await detect({ workspaceRoot })) {
      return read({ workspaceRoot });
    }
  }

  throw new ConvertError(
    "Could not determine package manager. Add `devEngines.packageManager` or legacy `packageManager` to `package.json`, or ensure a lockfile is present.",
    {
      type: "package_manager-unable_to_detect"
    }
  );
}

View on GitHub (pinned to 9f94a7d215)

Solutions

  1. Declare the manager in package.json: "packageManager": "pnpm@9.1.0" or "devEngines": { "packageManager": { "type": "npm", "version": "10.4.0" } }
  2. Run one install with your manager so its lockfile exists, then retry
  3. Restore the lockfile from git history if it was accidentally deleted

Example fix

// before: package.json has neither field, no lockfile on disk
{}

// after
{
  "packageManager": "pnpm@9.1.0"
}
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync, readFileSync } from "node:fs";
import path from "node:path";

const lockfiles = ["package-lock.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"];
const root = path.resolve(dir);
const pkg = JSON.parse(readFileSync(path.join(root, "package.json"), "utf8"));
const declared = pkg?.devEngines?.packageManager ?? pkg?.packageManager;
const hasLockfile = lockfiles.some((f) => existsSync(path.join(root, f)));
if (!declared && !hasLockfile) {
  throw new Error("Declare a package manager or commit a lockfile before workspace detection");
}

Type guard

function isManagerUndetectedError(e: unknown): boolean {
  return e instanceof ConvertError && e.type === "package_manager-unable_to_detect";
}

Try / catch

try {
  await getWorkspaceDetails({ root });
} catch (e) {
  if (e instanceof ConvertError && e.type === "package_manager-unable_to_detect") {
    // prompt the user to pick a manager, write packageManager to package.json, retry
  } else throw e;
}

Prevention

When it happens

Trigger: A workspace with no recognized lockfile (package-lock.json, pnpm-lock.yaml, yarn.lock, bun.lockb/bun.lock, ...) and no devEngines.packageManager or legacy packageManager field in package.json.

Common situations: Fresh repo initialized but never installed; lockfile deleted or gitignored; obscure or internal managers (nub/aube) without their lockfiles present; package.json stripped by scaffolding.

Related errors


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