vercel/turborepo · error · ConvertError

package_manager-unexpected

package_manager-unexpected

Error message

Not a bun project

What it means

The bun manager's read() re-runs detect() (bun.lockb/bun.lock exists, or package.json declares bun) and throws ConvertError type package_manager-unexpected when the workspace is not a bun project. In the standard flow read() executes only after detect() passed, so this error indicates direct invocation or that workspace state changed between the two calls.

Source

Thrown at packages/turbo-workspaces/src/managers/bun.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 bun workspaces into generic format
*/
async function read(args: ReadArgs): Promise<Project> {
  const isBun = await detect(args);
  if (!isBun) {
    throw new ConvertError("Not a bun 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. Use getWorkspaceDetails() so detection picks the right manager before read() runs
  2. Guard direct calls with MANAGERS.bun.detect({ workspaceRoot }) and skip on false
  3. If the project should be bun, restore bun.lock/bun.lockb or declare bun in package.json first

Example fix

// before
const project = await MANAGERS.bun.read({ workspaceRoot }); // no bun lockfile

// after
if (await MANAGERS.bun.detect({ workspaceRoot })) {
  const project = await MANAGERS.bun.read({ workspaceRoot });
} else {
  throw new Error(`Expected a bun workspace at ${workspaceRoot}`);
}
Defensive patterns

Strategy: validation

Validate before calling

if (await MANAGERS.bun.detect({ workspaceRoot })) {
  const project = await MANAGERS.bun.read({ workspaceRoot });
} else {
  throw new Error(`Refusing bun read: ${workspaceRoot} has no bun lockfile or declaration`);
}

Type guard

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

Try / catch

try {
  const project = await MANAGERS.bun.read({ workspaceRoot });
} catch (e) {
  if (e instanceof ConvertError && e.type === "package_manager-unexpected") {
    // workspace is not bun-managed; use getWorkspaceDetails() for generic detection
  } else throw e;
}

Prevention

When it happens

Trigger: Calling MANAGERS.bun.read({ workspaceRoot }) on a repo with no bun.lockb/bun.lock and no bun packageManager declaration; deleting the lockfile between detection and read.

Common situations: Direct API use in scripts or tests on non-bun fixtures; a stale Project/workspaceRoot captured before the user switched package managers.

Related errors


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