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 command

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Use valid PEP 440 specifier syntax: ">=1.0.0", "~=1.2", or comma-separated ">=1.0,<2.0".
  2. Replace npm-style ^/~ ranges with PEP 440 equivalents (~=x.y.z).
  3. 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

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


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/ec6c033f72af672c. Report an issue: GitHub.