github/spec-kit · error · ValidationError
Invalid extension.category: must be a non-empty string
Error message
Invalid extension.category: must be a non-empty string
What it means
The optional extension.category field, when present, must be a non-empty string (after strip). It is free-form (any non-blank text is accepted) but a blank string, null-adjacent value, or non-string (list, number) fails validation.
Source
Thrown at src/specify_cli/extensions/__init__.py:331
)
# 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"]
if not isinstance(requires, dict):
raise ValidationError(
f"Invalid requires: expected a mapping, got {type(requires).__name__}"
)
if "speckit_version" not in requires:View on GitHub (pinned to bf88c9f9a8)
Solutions
- Provide a meaningful non-empty category, e.g. `category: tooling`.
- Or delete the category key entirely — it is optional and absence passes validation.
- Ensure the value is a plain quoted string, not a list or blank.
Example fix
# before category: "" # after category: tooling
Defensive patterns
Strategy: validation
Validate before calling
def valid_category(cat: object) -> bool:
return not isinstance(cat, str) or bool(cat.strip()) # absent is OK; if present must be non-blank str
def category_ok(data: dict) -> bool:
cat = data.get("extension", {}).get("category")
return cat is None or (isinstance(cat, str) and cat.strip()) Type guard
def is_nonempty_str(v: object) -> bool:
return isinstance(v, str) and bool(v.strip()) Prevention
- Either fill category with a real label or delete the key — empty placeholders fail.
- Use a YAML schema validator (e.g. yamllint plus a jsonschema for extension.yml) in CI.
When it happens
Trigger: A manifest contains `category: ""`, `category: " "`, or `category: [tooling]`. The isinstance/strip check fails and ValidationError is raised during manifest load.
Common situations: Templates with a placeholder `category: ""` left unfilled, YAML flow syntax accidentally making category a list, or a commented-out category where a stray empty value remains.
Related errors
- Invalid extension ID '{ext['id']}': must be lowercase alphan
- Invalid version: {ext['version']}
- 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/f834468a2d9279c4.
Report an issue: GitHub.