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
- Declare the manager in package.json: "packageManager": "pnpm@9.1.0" or "devEngines": { "packageManager": { "type": "npm", "version": "10.4.0" } }
- Run one install with your manager so its lockfile exists, then retry
- 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
- Commit at least one lockfile and/or declare packageManager in package.json from day one
- Don't gitignore lockfiles in application repos
- Interactive tools should catch this error and offer to write the field for the user
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
- package_manager-unexpected
- package_manager-unexpected
- Unable to update README.md
- May not specify workspace name in non-root turbo.json
- New workspace root detected - unexpected 'workspaces' field
AI-assisted analysis of vercel/turborepo@9f94a7d215 (2026-08-16).
Data as JSON: /api/errors/6f6cfa79ff3ab379.
Report an issue: GitHub.