github/spec-kit · error · TemplateResolutionError
Template '{template_name}' has composing layers but no repla
Error message
Template '{template_name}' has composing layers but no replace base What it means
Layer composition requires exactly one base layer with strategy "replace" (an explicit replace candidate or the core template at .specify/templates/<name>.md) onto which prepend/append/wrap layers are applied. If only composing layers were found — no override file, no replace preset layer, and no core template — the function raises TemplateResolutionError instead of returning partial content.
Source
Thrown at scripts/python/common.py:513
return compose_from_base()
extensions_dir = repo_root / ".specify" / "extensions"
for extension_id in _sorted_extension_ids(extensions_dir):
extension_dir = extensions_dir / extension_id
candidate = _conventional_template(extension_dir, template_name)
if candidate is not None:
layers.append((candidate, "replace"))
return compose_from_base()
core = repo_root / ".specify" / "templates" / f"{template_name}.md"
if core.is_file():
layers.append((core, "replace"))
return compose_from_base()
if not layers:
return None
raise TemplateResolutionError(
f"Template '{template_name}' has composing layers but no replace base"
)
def get_invoke_separator(repo_root: Path) -> str:
integration_json = repo_root / ".specify" / "integration.json"
if not integration_json.is_file():
return "."
# Split the parse out of the lookup and guard the top-level shape, matching
# read_feature_json_feature_directory above and the bash/PowerShell twins,
# which both fall back to "." for any unusable integration.json:
# * a non-mapping top level ([], "forge", 42, null) is valid JSON, so
# json.JSONDecodeError never fires and state.get(...) raised
# AttributeError;
# * a non-UTF-8 file raises UnicodeDecodeError, which is a ValueError --
# not an OSError -- so it escaped the except tuple. Realistic on
# Windows, where PowerShell 5.1's Out-File/`>` default to UTF-16.
try:View on GitHub (pinned to bf88c9f9a8)
Solutions
- Restore or create the base template at .specify/templates/<template_name>.md (exact name from the error message).
- Alternatively add a layer with strategy: replace in the preset so the stack has a base.
- Check filename casing/spelling of both the requested template name and the files on disk.
Example fix
# before — only .specify/templates/presets/team/clarify.md (strategy: prepend), no base # after — also restore the base file # git checkout HEAD -- .specify/templates/clarify.md
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def has_replace_base(repo_root: Path, template_name: str, replace_layers: list[Path]) -> bool:
if replace_layers:
return True
return (repo_root / ".specify" / "templates" / f"{template_name}.md").is_file()
# guard before enabling prepend/append/wrap presets
assert has_replace_base(repo_root, name, replace_layers), "no replace base for layers" Try / catch
try:
content = resolve_template_content(name, repo_root)
except TemplateResolutionError as exc:
if "no replace base" in str(exc):
raise SystemExit(f"Restore the base template for {exc}") from exc
raise Prevention
- Never delete core .specify/templates/*.md files while keeping composing presets.
- When adding presets, verify a base (core template or a replace layer) exists.
- Treat template_name casing as significant — match filenames exactly.
When it happens
Trigger: A user creates .specify/templates/presets/<p>/<name>.md with strategy prepend/append/wrap but deletes or never creates the core .specify/templates/<name>.md and provides no replace layer; or the core template filename casing mismatches the requested template_name.
Common situations: Removing a stock template thinking presets alone are enough; renaming a template file but not the preset references; a typo in template_name so the core file lookup misses while preset layers with looser matching still hit.
Related errors
- Wrap layer {path} is missing {placeholder}
- Failed to parse preset manifest {manifest_path}: {exc}
- Unknown template composition strategy '{strategy}' in {path}
- Failed to read template layer for '{template_name}': {exc}
- No bundle.yml found in '{bundle_dir}'.
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/178cde08cc4e0f6c.
Report an issue: GitHub.