github/spec-kit · error · ValidationError
{singular.capitalize()} missing 'name' or 'file'
Error message
{singular.capitalize()} missing 'name' or 'file' What it means
A provides.templates/scripts entry is a mapping but is missing the required 'name' or 'file' key. Both are mandatory: 'name' is the artifact slug used by the resolver (e.g. PresetResolver._extension_manifest_declared_template returns the first match by name) and 'file' is the relative path inside the extension directory.
Source
Thrown at src/specify_cli/extensions/__init__.py:593
distinguishes template vs script) and 'strategy' (extension-provided
artifacts are always 'replace' -- see the forced-replace resolver
behavior for extension layers in presets/__init__.py). A present
'strategy' key is rejected rather than silently ignored, so an author
who copies a preset-style entry gets a clear error instead of a
silently-dropped field. Duplicate names within a section are also
rejected: the resolver returns the first matching entry by name
(``PresetResolver._extension_manifest_declared_template``), so a
later duplicate would be silently unreachable while still being
exposed by ``ExtensionManifest.templates``/``.scripts``.
"""
seen_names: set[str] = set()
for entry in entries:
if not isinstance(entry, dict):
raise ValidationError(
f"Each entry in 'provides.{section}' must be a mapping"
)
if "name" not in entry or "file" not in entry:
raise ValidationError(f"{singular.capitalize()} missing 'name' or 'file'")
name = entry["name"]
if not isinstance(name, str):
raise ValidationError(
f"Invalid {singular} name: expected a string, got {type(name).__name__}"
)
if not VALID_EXTENSION_ARTIFACT_NAME_PATTERN.match(name):
raise ValidationError(
f"Invalid {singular} name '{name}': "
"must be lowercase alphanumeric with hyphens only"
)
if name in seen_names:
raise ValidationError(
f"Duplicate {singular} name '{name}' in 'provides.{section}'"
)
seen_names.add(name)
file_value = entry["file"]View on GitHub (pinned to bf88c9f9a8)
Solutions
- Add both keys to every entry: "name": "<slug>", "file": "<relative-path>".
- Check for typos — the validator wants exactly 'name' and 'file'.
- If a template engine builds the manifest, assert {'name','file'} <= set(entry) for each entry before writing.
Example fix
// before
{ "name": "plan", "path": "templates/plan.md" }
// after
{ "name": "plan", "file": "templates/plan.md" } Defensive patterns
Strategy: validation
Validate before calling
for section in ("templates", "scripts"):
for entry in manifest.get("provides", {}).get(section, []):
if isinstance(entry, dict):
missing = {"name", "file"} - entry.keys()
assert not missing, f"{section} entry missing {missing}: {entry!r}" Type guard
def has_name_and_file(entry: object) -> bool:
return isinstance(entry, dict) and "name" in entry and "file" in entry Try / catch
try:
ExtensionManifest.load(path)
except ValidationError as e:
if "missing 'name' or 'file'" in str(e):
# add the missing key (exact names: 'name', 'file') and retry
... Prevention
- Memorize the two mandatory keys: name (slug) and file (relative path).
- Watch for typo'd keys like 'path' or 'id'.
- Assert {'name','file'} <= set(entry) in manifest generators.
When it happens
Trigger: {"file": "templates/plan.md"} (no name), {"name": "plan"} (no file), or a typo'd key like "filename". Raised immediately after the mapping check in the artifact validator.
Common situations: Typos in key names ('path' instead of 'file', 'id' instead of 'name'); partial copy-paste from another manifest; key silently dropped by a template engine leaving an empty value context.
Related errors
- Manifest must be a YAML mapping, got {type(data).__name__}:
- Missing required field: {field}
- Invalid extension: expected a mapping, got {type(ext).__name
- Missing extension.{field}
- Invalid extension.{field}: expected a string, got {type(ext[
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/c5a67ed6f912bc5b.
Report an issue: GitHub.