github/spec-kit · error · PresetCompatibilityError
Invalid version specifier: expected a string, got {type(requ
Error message
Invalid version specifier: expected a string, got {type(required).__name__} ({required!r}) What it means
check_compatibility rejects a manifest whose requires.speckit_version is not a string. This is defense in depth: the manifest validator already rejects non-string values, but check_compatibility is public and callable with a hand-built PresetManifest, so it re-checks and reports the offending type and value rather than letting packaging's SpecifierSet raise an opaque TypeError.
Source
Thrown at src/specify_cli/presets/__init__.py:808
manifest: Preset manifest
speckit_version: Current spec-kit version
Returns:
True if compatible
Raises:
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(View on GitHub (pinned to bf88c9f9a8)
Solutions
- Ensure requires.speckit_version is a string specifier such as ">=1.2.0", even in hand-built manifest objects.
- In preset.yml, always quote the specifier: `speckit_version: ">=1.0.0"` (a bare number YAML-parses to int/float).
- Catch PresetCompatibilityError around check_compatibility when manifests come from untrusted sources.
Example fix
# before manifest = PresetManifest(path) manifest.data["requires"]["speckit_version"] = 2 # int # after manifest.data["requires"]["speckit_version"] = ">=2.0"
Defensive patterns
Strategy: type-guard
Validate before calling
req = manifest.requires_speckit_version
if not isinstance(req, str):
raise ValueError(f"requires.speckit_version must be str, got {type(req).__name__}") Type guard
def has_string_version_requirement(manifest) -> bool:
return isinstance(manifest.requires_speckit_version, str) Try / catch
try:
manager.check_compatibility(manifest, speckit_version)
except PresetCompatibilityError as e:
if "expected a string" in str(e):
# hand-built manifest has a non-string specifier; fix its data and retry
... Prevention
- Always quote version specifiers in YAML: speckit_version: ">=1.0.0" (bare numbers parse to int/float).
- In tests and tooling, build manifests from real preset.yml files or assert the field type first.
When it happens
Trigger: Constructing PresetManifest programmatically (or monkey-patching its requires_speckit_version) with an int/float/list/dict/None, then calling manager.check_compatibility(manifest, version). YAML sources hit the manifest validator instead, so this path is mostly tests and custom code.
Common situations: Test fixtures building manifests by hand with version=None, or tooling that injects a parsed YAML value (e.g. `>=1.0` quoted incorrectly becomes a string, but a bare numeric like `2` becomes int).
Related errors
- Invalid version specifier: {required}
- Preset requires spec-kit {required}, but {speckit_version} i
- Bundle '{manifest.bundle.id}' requires Spec Kit {manifest.re
- Cannot restore '{pack_id}': metadata must be a dict
- Failed to parse preset manifest {manifest_path}: {exc}
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/def2f0fcc0baac9a.
Report an issue: GitHub.