vercel/turborepo · error · ConvertError
package_manager-unexpected
package_manager-unexpected
Error message
Not a pnpm project
What it means
Thrown by the pnpm manager handler's read() in turbo-workspaces when pnpm's detect() returns false. Detection means: pnpm-lock.yaml exists OR pnpm-workspace.yaml exists OR the packageManager/devEngines.packageManager field declares pnpm. Note that a pnpm-workspace.yaml alone is enough to make detect() true, so read() can pass detection even with no lockfile. ConvertError type "package_manager-unexpected".
Source
Thrown at packages/turbo-workspaces/src/managers/pnpm.ts:62
const lockFile = path.join(args.workspaceRoot, PACKAGE_MANAGER_DETAILS.lock);
const workspaceFile = path.join(args.workspaceRoot, "pnpm-workspace.yaml");
const packageManager = getWorkspacePackageManager({
workspaceRoot: args.workspaceRoot
});
return (
fs.existsSync(lockFile) ||
fs.existsSync(workspaceFile) ||
packageManager === PACKAGE_MANAGER_DETAILS.name
);
}
/**
Read workspace data from pnpm workspaces into generic format
*/
async function read(args: ReadArgs): Promise<Project> {
const isPnpm = await detect(args);
if (!isPnpm) {
throw new ConvertError("Not a pnpm project", {
type: "package_manager-unexpected"
});
}
const { name, description } = getWorkspaceInfo(args);
return {
name,
description,
packageManager: PACKAGE_MANAGER_DETAILS.name,
paths: expandPaths({
root: args.workspaceRoot,
lockFile: PACKAGE_MANAGER_DETAILS.lock,
workspaceConfig: "pnpm-workspace.yaml"
}),
workspaceData: {
globs: getPnpmWorkspaces(args),
workspaces: expandWorkspaces({
workspaceGlobs: getPnpmWorkspaces(args),View on GitHub (pinned to 9f94a7d215)
Solutions
- Ensure pnpm-lock.yaml or pnpm-workspace.yaml exists at the root (run `pnpm install` to regenerate the lockfile), then retry
- Add "packageManager": "pnpm@<version>" or devEngines.packageManager: { "name": "pnpm", "version": "<range>" } to root package.json so detection does not rely on lockfiles
- Prefer getWorkspaceDetails({ root }) over MANAGERS.pnpm.read so the manager matching the actual files wins
- Re-run the migration after any concurrent checkout/clean finishes so detection and read agree
Example fix
// before
const project = await MANAGERS.pnpm.read({ workspaceRoot: root }); // throws if no markers
// after
if (await MANAGERS.pnpm.detect({ workspaceRoot: root })) {
const project = await MANAGERS.pnpm.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";
const markers = ["pnpm-lock.yaml", "pnpm-workspace.yaml"].map(f =>
path.join(root, f)
);
if (!markers.some(existsSync)) {
throw new Error(`${root} has no pnpm-lock.yaml / pnpm-workspace.yaml`);
}
const project = await MANAGERS.pnpm.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.pnpm.read({ workspaceRoot: root });
} catch (err) {
if (err instanceof ConvertError && err.type === "package_manager-unexpected") {
project = await getWorkspaceDetails({ root });
} else {
throw err;
}
} Prevention
- Commit pnpm-lock.yaml and pnpm-workspace.yaml so every checkout is detectable
- Add "packageManager": "pnpm@<version>" for lockfile-independent detection
- Use getWorkspaceDetails unless you have specifically confirmed the project is pnpm
- Do not run git clean/checkouts concurrently with migration
When it happens
Trigger: Calling MANAGERS.pnpm.read({ workspaceRoot }) directly on a root that has none of pnpm-lock.yaml, pnpm-workspace.yaml, or a pnpm declaration; via getWorkspaceDetails()/convert() only when those markers disappear between detect() and read() (concurrent git clean, lockfile deletion, or package.json rewrite during the run).
Common situations: pnpm-lock.yaml and pnpm-workspace.yaml gitignored or wiped by a clean script, leaving only an ambiguous project; the packageManager field removed when corepack was disabled or the field stripped during a merge; passing a wrong workspaceRoot (e.g. the git toplevel when the pnpm root is a subdirectory); hand-rolling detection with only `which pnpm` and assuming a global pnpm implies a pnpm project.
Related errors
- package_manager-unexpected
- package_manager-unexpected
- package_manager-unexpected
- pnpm-workspace_parse_error
- New workspace root detected - unexpected pnpm-workspace.yaml
AI-assisted analysis of vercel/turborepo@9f94a7d215 (2026-08-16).
Data as JSON: /api/errors/30ad6692090bb26b.
Report an issue: GitHub.