github/spec-kit · error · ValidationError
Missing requires.speckit_version
Error message
Missing requires.speckit_version
What it means
The requires mapping must contain the key speckit_version. This is the only required entry in requires and is what check_compatibility() later feeds into packaging SpecifierSet to decide whether the installed Spec Kit version can run the extension.
Source
Thrown at src/specify_cli/extensions/__init__.py:350
"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"]
if not isinstance(requires, dict):
raise ValidationError(
f"Invalid requires: expected a mapping, got {type(requires).__name__}"
)
if "speckit_version" not in requires:
raise ValidationError("Missing requires.speckit_version")
# Presence alone is not enough: check_compatibility() feeds this value to
# ``SpecifierSet(required)``, guarded only by ``except InvalidSpecifier``,
# which a non-string escapes two different ways. A float/int/bool/None
# raises TypeError from the constructor, while a list or dict is an
# *iterable*, so SpecifierSet accepts it and the failure surfaces much
# later as ``AttributeError: 'str' object has no attribute 'filter'`` from
# inside .contains(). Neither is a CompatibilityError, so both bypass the
# CLI's "Compatibility Error" handler and exit 1 with a raw traceback
# naming no field. An unquoted ``speckit_version: 1.0`` is an easy YAML
# slip. Mirrors the sibling IntegrationDescriptor, which already requires
# a non-empty string here.
if (
not isinstance(requires["speckit_version"], str)
or not requires["speckit_version"].strip()
):
raise ValidationError(
"Invalid requires.speckit_version: expected a non-empty string, "
f"got {type(requires['speckit_version']).__name__}"View on GitHub (pinned to bf88c9f9a8)
Solutions
- Add `speckit_version` under requires with a PEP 440 specifier string, e.g. `speckit_version: ">=1.0.0"`.
- Fix the key spelling — it must be exactly speckit_version, snake_case.
- Pick the specifier from your extension's actual minimum supported Spec Kit version.
Example fix
# before requires: speckit-ver: '>=1.0.0' # after requires: speckit_version: ">=1.0.0"
Defensive patterns
Strategy: validation
Validate before calling
def has_speckit_version(data: dict) -> bool:
return "speckit_version" in data.get("requires", {}) Prevention
- The key is exactly `speckit_version` — snake_case, no hyphens.
- Scaffold new extensions from a bundled one so required keys come pre-filled.
When it happens
Trigger: A manifest has `requires: {}`, or a misspelled key like `requires:\n speckit-ver: '>=1'` or `specify_version:`. The membership test `"speckit_version" not in requires` fires.
Common situations: Typos in the key (speckit-ver, speckitversion, specify_version), or an empty requires block left from a template.
Related errors
- Extension must provide at least one command, hook, or event
- Hook '{hook_name}' missing required 'command' field
- Each command entry in 'provides.commands' must be a mapping
- Missing required field: {field}
- Missing extension.{field}
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/6fc02487f7e4aa83.
Report an issue: GitHub.