{"record":{"id":"b89e76ac0f91016d","repo":"moeru-ai/airi","slug":"invalid-semver-version","errorCode":null,"errorMessage":"Invalid semver: ${version}","messagePattern":"Invalid semver: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"integrations/vscode/vscode-airi/scripts/shared.ts","lineNumber":50,"sourceCode":"      json.version = originalVersion\n\n      await writeFile(new URL('../package.json', import.meta.url), `${JSON.stringify(json, null, 2)}\\n`, 'utf-8')\n    },\n  }\n}\n\n// NOTICE: VSCE rejects prerelease identifiers, so we encode stage+sequence into a numeric-only patch bucket:\n//   encodedPatch = patch*10000 + stageBucket + sequence.\n//   stageBucket: alpha=1000, beta=2000, rc=3000, stable=9000.\n//   Examples:\n//     0.8.0-alpha.6 -> 0.8.(0*10000+1000+6)=0.8.1006 (preview=true)\n//     0.8.0-beta.1 -> 0.8.2001 (preview=true)\n//     0.8.0        -> 0.8.(0*10000+9000)=0.8.9000 (preview=false)\n//   This keeps ordering: alpha < beta < rc < stable. Unknown prerelease tags default to alpha.\nexport function encodeNumericVersion(version: string) {\n  const match = version.match(/^(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)(-(?<pre>[0-9A-Z.-]+))?$/i)\n  if (!match || !match.groups)\n    throw new Error(`Invalid semver: ${version}`)\n\n  const major = Number.parseInt(match.groups.major, 10)\n  const minor = Number.parseInt(match.groups.minor, 10)\n  const patch = Number.parseInt(match.groups.patch, 10)\n  const prerelease = match.groups.pre\n\n  const multiplier = 10_000\n  const stageBuckets = {\n    alpha: 1_000,\n    beta: 2_000,\n    rc: 3_000,\n    stable: 9_000,\n  } as const\n\n  const { stage, sequence } = parsePrerelease(prerelease)\n  const maxSequence = (multiplier - 1) - stageBuckets[stage]\n  if (sequence > maxSequence) {\n    throw new Error(`Prerelease sequence overflow for ${stage}: ${sequence} exceeds limit ${maxSequence}`)","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/integrations/vscode/vscode-airi/scripts/shared.ts#L32-L68","documentation":"encodeNumericVersion encodes a semver string into VSCE-compatible numeric-only patch form for the VS Code marketplace. It throws 'Invalid semver' when the input does not match the strict regex ^major.minor.patch(-prerelease)?$, case-insensitive. Leading 'v', missing patch component, build metadata, or non-numeric components all fail.","triggerScenarios":"Passing 'v1.2.3' (leading v), '1.2' (no patch), '1.2.3.4' (extra component), '1.2.3+build' (build metadata not in regex), '' (empty), or any value where major/minor/patch are non-numeric.","commonSituations":"package.json version was edited manually and malformed; a git tag like 'v0.8.0' is passed verbatim without stripping the v; an external release tool emits a non-semver version string into the encode step.","solutions":["Strip a leading 'v' before calling encodeNumericVersion if the input comes from git tags.","Ensure the version string has exactly three numeric dot-separated components with an optional -prerelease suffix.","Validate with a semver library (or this same regex) before invoking the encoder and surface a clearer upstream error.","Check the package.json/build pipeline that produces the version string."],"exampleFix":"// before\nconst { version, preview } = encodeNumericVersion(rawVersion)\n\n// after\nconst cleaned = rawVersion.replace(/^v/i, '')\nif (!/^(\\d+)\\.(\\d+)\\.(\\d+)(-[0-9A-Z.-]+)?$/i.test(cleaned)) {\n  throw new Error(`Version is not valid semver (major.minor.patch[-pre]): ${rawVersion}`)\n}\nconst { version, preview } = encodeNumericVersion(cleaned)","handlingStrategy":"validation","validationCode":"const SEMVER_RE = /^(\\d+)\\.(\\d+)\\.(\\d+)(-[0-9A-Za-z.-]+)?$/\nfunction assertSemver(version: string) {\n  const v = version.replace(/^v/i, '')\n  if (!SEMVER_RE.test(v)) {\n    throw new Error(`Not a valid semver string: ${version}`)\n  }\n  return v\n}","typeGuard":"function isSemverLike(version: unknown): version is string {\n  return typeof version === 'string'\n    && /^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z.-]+)?$/.test(version.replace(/^v/i, ''))\n}","tryCatchPattern":"try {\n  return encodeNumericVersion(raw.replace(/^v/i, ''))\n}\ncatch (err) {\n  throw new Error(`Cannot encode version for VSCE: ${(err as Error).message}`)\n}","preventionTips":["Strip a leading 'v' from git-tag-derived versions before encoding.","Run package.json version through a semver library before passing to encodeNumericVersion.","Assert the version in CI before publishing."],"tags":["semver","validation","vscode","build","vsce"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}