github/spec-kit · error · ValidationError
Invalid version: {ext['version']}
Error message
Invalid version: {ext['version']} What it means
The extension.version field cannot be parsed by packaging.version.Version, so it is not a valid version string. Spec Kit requires PEP 440-compatible versions so compatibility checks (requires.speckit_version ranges, upgrade prompts) can compare versions.
Source
Thrown at src/specify_cli/extensions/__init__.py:326
raise ValidationError(f"Missing extension.{field}")
if not isinstance(ext[field], str):
raise ValidationError(
f"Invalid extension.{field}: expected a string, "
f"got {type(ext[field]).__name__}"
)
# Validate extension ID format
if not re.match(r"^[a-z0-9-]+$", ext["id"]):
raise ValidationError(
f"Invalid extension ID '{ext['id']}': "
"must be lowercase alphanumeric with hyphens only"
)
# Validate semantic version
try:
pkg_version.Version(ext["version"])
except pkg_version.InvalidVersion:
raise ValidationError(f"Invalid version: {ext['version']}")
# Validate optional category field (free-form string)
if "category" in ext:
if not isinstance(ext["category"], str) or not ext["category"].strip():
raise ValidationError(
"Invalid extension.category: must be a non-empty string"
)
# Validate optional effect field
if "effect" in ext:
if not isinstance(ext["effect"], str) or ext["effect"] not in VALID_EFFECTS:
raise ValidationError(
f"Invalid extension.effect '{ext.get('effect')}': "
f"must be one of {sorted(VALID_EFFECTS)}"
)
# Validate requires section
requires = self.data["requires"]View on GitHub (pinned to bf88c9f9a8)
Solutions
- Use a PEP 440 version such as `version: '0.1.0'` or `version: '2.3.1'`.
- If you need semver prereleases, write them PEP 440 style: `1.0.0a1` or `1.0.0-beta.1` (both parse).
- Quote the version string in extension.yml so YAML does not coerce it to a float/int.
Example fix
# before version: latest # after version: '0.1.0'
Defensive patterns
Strategy: validation
Validate before calling
from packaging import version
def valid_ext_version(v: object) -> bool:
if not isinstance(v, str):
return False
try:
version.Version(v)
return True
except version.InvalidVersion:
return False Type guard
def is_pep440_version(v: object) -> bool:
try:
version.Version(v) if isinstance(v, str) else None
return isinstance(v, str)
except Exception:
return False Try / catch
try:
ExtensionManifest.load(path)
except ValidationError as e:
if "Invalid version" in str(e):
fix_version_field(path) Prevention
- Always quote version strings in YAML to prevent float coercion.
- Run `python -c "from packaging.version import Version; Version(open('extension.yml').read())"`-style checks in a pre-commit hook.
When it happens
Trigger: A manifest declares `version: '1.0'` unquoted-in-invalid-form, `version: latest`, `version: v1.0.0-alpha` with stray text, or `version: 1.0.0.0.1`. pkg_version.Version(ext["version"]) raises InvalidVersion, which is converted to this ValidationError.
Common situations: Using `latest` or a git SHA as version, prefixing with `v`, or YAML auto-parsing `version: 1.0` into a float that stringifies as `1.0` (valid) but `version: 1.0.0.0.1` (invalid PEP 440) failing. Also copy-pasting semver-only prerelease syntax that PEP 440 rejects.
Related errors
- Invalid extension ID '{ext['id']}': must be lowercase alphan
- Invalid extension.category: must be a non-empty string
- Invalid extension.effect '{ext.get('effect')}': must be one
- Invalid requires: expected a mapping, got {type(requires).__
- Missing requires.speckit_version
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/dfae657dc2ac066b.
Report an issue: GitHub.