github/spec-kit · error · PresetCompatibilityError
Invalid version specifier: {required}
Error message
Invalid version specifier: {required} What it means
check_compatibility could not parse the requires.speckit_version string as a PEP 440 specifier set — packaging.SpecifierSet raised InvalidSpecifier. The value is a string but syntactically invalid, e.g. missing an operator or using unsupported syntax.
Source
Thrown at src/specify_cli/presets/__init__.py:815
PresetCompatibilityError: If pack is incompatible
"""
required = manifest.requires_speckit_version
# Defense in depth: the manifest validator now rejects a non-string
# requires.speckit_version, but this method is public and also reachable
# with a hand-built manifest object. ``InvalidSpecifier`` alone does not
# cover a non-string -- scalars raise TypeError from the constructor, and
# a list/dict is iterable so it constructs here and only breaks inside
# .contains(). Reject up front so this always reports a
# PresetCompatibilityError.
if not isinstance(required, str):
raise PresetCompatibilityError(
"Invalid version specifier: expected a string, got "
f"{type(required).__name__} ({required!r})"
)
try:
SpecifierSet(required) # Just to validate
except InvalidSpecifier:
raise PresetCompatibilityError(f"Invalid version specifier: {required}")
if not version_satisfies(speckit_version, required):
raise PresetCompatibilityError(
f"Preset requires spec-kit {required}, "
f"but {speckit_version} is installed.\n"
f"Upgrade spec-kit with: {REINSTALL_COMMAND}"
)
return True
def _register_commands(
self,
manifest: PresetManifest,
preset_dir: Path
) -> Dict[str, List[str]]:
"""Register preset command overrides with all detected AI agents.
Scans the preset's templates for type "command", reads each commandView on GitHub (pinned to bf88c9f9a8)
Solutions
- Use valid PEP 440 specifier syntax: ">=1.0.0", "~=1.2", or comma-separated ">=1.0,<2.0".
- Replace npm-style ^/~ ranges with PEP 440 equivalents (~=x.y.z).
- Test your specifier quickly: `python -c "from packaging.specifiers import SpecifierSet; SpecifierSet('>=1.0')"`.
Example fix
# before (preset.yml) requires: speckit_version: "^1.2" # after requires: speckit_version: ">=1.2,<2.0"
Defensive patterns
Strategy: validation
Validate before calling
from packaging.specifiers import SpecifierSet, InvalidSpecifier
try:
SpecifierSet(required)
except InvalidSpecifier:
raise ValueError(f"bad specifier {required!r}: use PEP 440 like '>=1.0,<2.0'") Type guard
from packaging.specifiers import SpecifierSet, InvalidSpecifier
def is_valid_specifier(s: str) -> bool:
try:
SpecifierSet(s)
return True
except InvalidSpecifier:
return False Try / catch
try:
manager.check_compatibility(manifest, speckit_version)
except PresetCompatibilityError as e:
if "Invalid version specifier" in str(e):
# rewrite requires.speckit_version in valid PEP 440 syntax and retry
... Prevention
- Every clause needs an operator: >=, <=, ~=, ==, != — never a bare version.
- PEP 440 has no ^ or ~ npm-style ranges; expand them to explicit bounds.
- Validate specifiers in CI with packaging.SpecifierSet before publishing a preset.
When it happens
Trigger: requires.speckit_version set to something like "1.0" (bare version with no operator), "==>2.0", or "version>=2". SpecifierSet requires operator-prefixed clauses such as ">=1.0,<2.0".
Common situations: Writing just the version number instead of a specifier, or mixing npm-style syntax (^1.2, ~2.1) — PEP 440 does not support caret/tilde ranges.
Related errors
- Invalid version specifier: expected a string, got {type(requ
- Preset requires spec-kit {required}, but {speckit_version} i
- Bundle '{manifest.bundle.id}' requires Spec Kit {manifest.re
- Failed to parse preset manifest {manifest_path}: {exc}
- Wrap layer {path} is missing {placeholder}
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/ec6c033f72af672c.
Report an issue: GitHub.