headroomlabs-ai/headroom · error · ValueError
Invalid semantic version: {value}
Error message
Invalid semantic version: {value} What it means
Raised by SemVer.parse() when the input string does not match the semantic version regex (major.minor.patch of non-negative integers). The release-version tooling uses strict parsing so that malformed tags never silently produce a wrong bump. Note it accepts plain X.Y.Z only; 4-component legacy tags must go through parse_release_tag().
Source
Thrown at headroom/release_version.py:58
FIELD_SEP = "\x1f"
RECORD_SEP = "\x1e"
GIT_LOG_FORMAT = "%s%x1f%b%x1e"
BUMP_PRIORITY = {"patch": 0, "minor": 1, "major": 2}
@dataclass(frozen=True, order=True)
class SemVer:
"""Semantic version tuple with simple bump helpers."""
major: int
minor: int
patch: int
@classmethod
def parse(cls, value: str) -> SemVer:
match = SEMVER_RE.match(value)
if not match:
raise ValueError(f"Invalid semantic version: {value}")
return cls(*(int(part) for part in match.groups()))
def bump(self, level: str) -> SemVer:
if level == "major":
return SemVer(self.major + 1, 0, 0)
if level == "minor":
return SemVer(self.major, self.minor + 1, 0)
if level == "patch":
return SemVer(self.major, self.minor, self.patch + 1)
raise ValueError(f"Unsupported bump level: {level}")
def __str__(self) -> str:
return f"{self.major}.{self.minor}.{self.patch}"
@dataclass(frozen=True)
class ReleaseVersionInfo:
"""Workflow outputs for release version calculation."""View on GitHub (pinned to 322425c43b)
Solutions
- Strip the leading 'v' and any build/prerelease suffix before parsing: tag.lstrip('v').split('+')[0].split('-')[0].
- For 4-component legacy tags use parse_release_tag()/normalize_release_tag() instead of SemVer.parse().
- Validate the tag format in CI before calling the release tooling.
Example fix
# before
semver = SemVer.parse(git_tag) # git_tag = 'v1.2.3'
# after
semver = SemVer.parse(git_tag.lstrip('v')) Defensive patterns
Strategy: validation
Validate before calling
import re
SEMVER = re.compile(r'^\d+\.\d+\.\d+$')
tag = git_tag.lstrip('v')
if not SEMVER.match(tag):
raise ValueError(f'not a plain X.Y.Z version: {git_tag!r}')
semver = SemVer.parse(tag) Type guard
import re
def is_plain_semver(value: str) -> bool:
return re.match(r'^\d+\.\d+\.\d+$', value) is not None Try / catch
try:
semver = SemVer.parse(tag.lstrip('v'))
except ValueError as e:
raise ReleaseError(f'unparseable tag {tag!r}: {e}') from e Prevention
- Strip the 'v' prefix from git tags before parsing.
- Route 4-component legacy tags through parse_release_tag(), not SemVer.parse().
- Enforce a tag naming convention in CI (protected tag rules).
When it happens
Trigger: Calling SemVer.parse('1.2'), SemVer.parse('v1.2.3') (leading 'v'), SemVer.parse('1.2.3-beta') (prerelease suffix), or SemVer.parse('latest').
Common situations: Passing git tag refs like 'v1.2.3' without stripping the prefix; feeding legacy 4-part tags ('1.2.3.4') to the wrong parser; passing branch names or 'latest' aliases from a CI variable.
Related errors
- Unsupported bump level: {level}
- Invalid release tag: {tag}
- invalid pipeline config TOML: {0}
- recommendations file not found: {0}
- bedrock_eventstream_parse_failed
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/5c2a8da72c363983.
Report an issue: GitHub.