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
- List valid targets: `npm view turbo dist-tags --json` and `npm view turbo versions --json --last 20`
- 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`
- 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
- Resolve `--to` values from `npm view turbo dist-tags`/`versions` output rather than typing them from memory
- Accept exact versions or known tags only — ranges like ^2.3.0 are always rejected
- Script the migration to default to `latest` when the requested target is unknown
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
- Unable to fetch the latest version of ${packageName}
- Invalid version: ${version}
- Invalid task name found in turbo.json.
- New workspace is missing a package.json file
- Invalid example name: ${name}
AI-assisted analysis of vercel/turborepo@9f94a7d215 (2026-08-16).
Data as JSON: /api/errors/c81b4a107d84ae09.
Report an issue: GitHub.