vercel/turborepo · error · Error

turbo@${to} does not exist

Error message

turbo@${to} does not exist

What it means

When `turbo-codemod migrate` is given `--to <target>`, getLatestVersion accepts the value only if it is a known dist-tag (resolved via dist-tags, e.g. `latest`, `canary`) or an exact version present in the published `versions` map. Anything else throws `turbo@<to> does not exist`.

Source

Thrown at packages/turbo-codemod/src/commands/migrate/steps/get-latest-version.ts:42

    throw new Error(`Unable to fetch the latest version of ${packageName}`);
  }
}

export async function getLatestVersion({
  to
}: MigrateCommandOptions): Promise<string | undefined> {
  const packageDetails = await getPackageDetails({ packageName: "turbo" });
  const { "dist-tags": tags, versions } = packageDetails;

  if (to) {
    // If 'to' is a dist-tag (e.g. "latest", "canary"), resolve to the concrete version
    if (tags[to]) {
      return tags[to];
    }
    if (to in versions) {
      return to;
    }
    throw new Error(`turbo@${to} does not exist`);
  }

  return tags.latest;
}

View on GitHub (pinned to 9f94a7d215)

Solutions

  1. List valid targets: `npm view turbo dist-tags --json` and `npm view turbo versions --json --last 20`
  2. Re-run with a value that appears in one of those lists, e.g. `npx @turbo/codemod migrate --to latest` or `--to 2.3.17`
  3. Omit --to entirely to accept `tags.latest` automatically

Example fix

# before
npx @turbo/codemod migrate --to 2.99.99
# after
npm view turbo dist-tags   # find a real tag/version
npx @turbo/codemod migrate --to latest
Defensive patterns

Strategy: validation

Validate before calling

import { execSync } from 'node:child_process';

function isValidTurboTarget(target: string): boolean {
  const tags = JSON.parse(execSync('npm view turbo dist-tags --json').toString());
  const versions = new Set(JSON.parse(execSync('npm view turbo versions --json').toString()));
  return target in tags || versions.has(target);
}

Type guard

function isDistTagOrExactVersion(target: string, distTags: Record<string, string>, versions: string[]): boolean {
  return target in distTags || versions.includes(target);
}

Try / catch

try {
  await migrate({ to });
} catch (err) {
  if (err instanceof Error && /does not exist/.test(err.message)) {
    const tags = await npmView('turbo', 'dist-tags');
    to = tags.latest; // fall back to a known-good target and re-run
    return migrate({ to });
  }
  throw err;
}

Prevention

When it happens

Trigger: Running migrate with an unpublished version (`--to 99.9.9`), a typo (`--to 2.3.4x`), a range (`--to ^2.3.0`), or an unknown tag name (`--to stable`).

Common situations: Assuming a tag exists because another tool uses it; copy-pasting a version from a blog post that was never released; guessing at the next canary version.

Related errors


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