{"record":{"id":"e56dadd4700ede9b","repo":"vercel/turborepo","slug":"invalid-version-version","errorCode":null,"errorMessage":"Invalid version: ${version}","messagePattern":"Invalid version: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/turbo-codemod/src/transforms/update-versioned-schema-json.ts","lineNumber":104,"sourceCode":" * Replaces dots with hyphens to create a valid DNS subdomain.\n * e.g., \"2.7.5\" -> \"v2-7-5\", \"2.9.4-canary.5\" -> \"v2-9-4-canary-5\"\n */\nfunction versionToSubdomain(version: string): string {\n  return `v${version.replaceAll(\".\", \"-\")}`;\n}\n\n/**\n * Generates the new versioned schema URL.\n * Uses semver.parse to preserve prerelease identifiers (e.g., canary.5),\n * falling back to semver.coerce for non-standard version strings.\n */\nexport function getVersionedSchemaUrl(version: string): string {\n  // parse preserves prerelease: \"2.9.4-canary.5\" -> \"2.9.4-canary.5\"\n  // coerce strips it: \"2.9.4-canary.5\" -> \"2.9.4\"\n  const parsed = parse(version);\n  const resolved = parsed ? parsed.version : coerce(version)?.version;\n  if (!resolved) {\n    throw new Error(`Invalid version: ${version}`);\n  }\n  const subdomain = versionToSubdomain(resolved);\n  return `https://${subdomain}.turborepo.dev/schema.json`;\n}\n\n/**\n * Updates any old schema URLs in file content to the new versioned URL\n */\nfunction updateSchemaUrls(content: string, newUrl: string): string {\n  let updated = content;\n  // Replace static old URLs\n  for (const oldUrl of OLD_SCHEMA_URLS) {\n    updated = updated.replaceAll(oldUrl, newUrl);\n  }\n  // Replace outdated versioned URLs (e.g., v2-7-4 -> v2-7-5)\n  updated = updated.replaceAll(VERSIONED_SCHEMA_URL_REGEX, newUrl);\n  return updated;\n}","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/vercel/turborepo/blob/f9245100cf0d31d96628804ead485f6bf226e55a/packages/turbo-codemod/src/transforms/update-versioned-schema-json.ts#L86-L122","documentation":"During migration, the update-versioned-schema-json transform builds the new schema.json URL from the resolved turbo version. It parses the version with semver.parse to keep prerelease parts, and falls back to semver.coerce for loose strings. It throws this Error only when both fail, which means the version is not recognizable as semver at all.","triggerScenarios":"getVersionedSchemaUrl receives a string with no leading numeric version, such as \"banana\", \"v\", or \"\". semver.parse returns null and semver.coerce also returns null, so resolved is undefined and it throws.","commonSituations":"A package.json or lockfile contains a corrupted turbo version. A script passes a branch name or arbitrary string where a version belongs. An empty version string after a failed earlier step.","solutions":["Check the version you passed with --to and correct it to a semver string such as 2.9.4 or 2.9.4-canary.5","Inspect your package.json for a malformed turbo version and fix it to a real published version","Re-run the codemod after correcting the source of the version string"],"exampleFix":"// before\n getVersionedSchemaUrl(\"main\");\n// after\ngetVersionedSchemaUrl(\"2.9.4-canary.5\"); // \"https://2-9-4-canary-5.turborepo.dev/schema.json\"","handlingStrategy":"type-guard","validationCode":"import semver from \"semver\";\n\n// accept only versions that parse or coerce before generating schema URLs\nfunction assertResolvableVersion(version: string): void {\n  if (!semver.parse(version) && !semver.coerce(version)) {\n    throw new Error(`Invalid version: ${version}`);\n  }\n}","typeGuard":"import semver from \"semver\";\n\nfunction isResolvableSemver(version: string): boolean {\n  return semver.parse(version) !== null || semver.coerce(version) !== null;\n}","tryCatchPattern":null,"preventionTips":["Validate version strings with semver.valid or semver.coerce before use","Source versions from package.json or the registry, never free-text input","Reject branch names and commit SHAs in version fields during code review"],"tags":["turbo-codemod","semver","version","schema-url","migration"],"backgroundTag":"invalid-semver","analyzedSha":"f9245100cf0d31d96628804ead485f6bf226e55a","analyzedAt":"2026-08-17T10:46:15.696Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}