github/spec-kit · error · PresetValidationError
Wrap strategy in '{layer['source']}' is missing the {placeho
Error message
Wrap strategy in '{layer['source']}' is missing the {placeholder} placeholder. The wrapper must contain {placeholder} to indicate where the lower-priority content should be inserted. What it means
A preset layer using the 'wrap' merge strategy does not contain the required placeholder marking where lower-priority content goes: '$CORE_SCRIPT' for script templates, '{CORE_TEMPLATE}' for others. Without the placeholder the substitution target is undefined, so layer composition raises PresetValidationError instead of guessing.
Source
Thrown at src/specify_cli/presets/__init__.py:5851
if strategy == "replace":
top_frontmatter_text = fm
base_frontmatter_text = fm
elif fm:
top_frontmatter_text = fm
if strategy == "replace":
content = layer_content
elif strategy == "prepend":
content = layer_content + "\n\n" + content
elif strategy == "append":
content = content + "\n\n" + layer_content
elif strategy == "wrap":
if template_type == "script":
placeholder = "$CORE_SCRIPT"
else:
placeholder = "{CORE_TEMPLATE}"
if placeholder not in layer_content:
raise PresetValidationError(
f"Wrap strategy in '{layer['source']}' is missing "
f"the {placeholder} placeholder. The wrapper must "
f"contain {placeholder} to indicate where the "
f"lower-priority content should be inserted."
)
content = layer_content.replace(placeholder, content)
# Reattach the highest-priority frontmatter for commands,
# inheriting scripts/agent_scripts from the base if missing
# and stripping the strategy key (internal-only, not for agent output).
if is_command and top_frontmatter_text:
def _parse_fm_yaml(fm_block: str) -> dict:
"""Parse YAML from a frontmatter block (with --- fences)."""
lines = fm_block.splitlines()
# Parse only interior lines (between --- fences)
if len(lines) >= 2:
yaml_lines = lines[1:-1]
else:View on GitHub (pinned to bf88c9f9a8)
Solutions
- Add the correct placeholder to the wrapper: $CORE_SCRIPT in script layers, {CORE_TEMPLATE} in markdown/command layers
- Check placeholder spelling and braces exactly — {CORE_TEMPLATE} uses braces, $CORE_SCRIPT uses a dollar prefix
- If you intended full replacement rather than wrapping, change the layer strategy to 'replace'
Example fix
# before (markdown wrap layer)
strategy: wrap
---
# My wrapper header
<!-- no placeholder -->
# after
strategy: wrap
---
# My wrapper header
{CORE_TEMPLATE} Defensive patterns
Strategy: validation
Validate before calling
placeholder = "$CORE_SCRIPT" if template_type == "script" else "{CORE_TEMPLATE}"
if layer["strategy"] == "wrap" and placeholder not in layer_content:
raise ValueError(f"wrap layer '{source}' missing {placeholder}") Type guard
def wrap_layer_is_valid(layer_content: str, template_type: str) -> bool:
ph = "$CORE_SCRIPT" if template_type == "script" else "{CORE_TEMPLATE}"
return ph in layer_content Try / catch
except PresetValidationError as e:
if "missing the" in str(e) and "placeholder" in str(e):
# report the layer source and expected placeholder to the author
raise PresetAuthoringError(layer_source, str(e)) from e
raise Prevention
- When authoring wrap layers, always include $CORE_SCRIPT (scripts) or {CORE_TEMPLATE} (other templates) exactly once
- Lint preset layers before publishing: wrap strategy requires the type-correct placeholder
- Use 'replace' strategy when the wrapper genuinely should discard lower-priority content
When it happens
Trigger: Authoring a preset overlay/extension template with strategy: wrap whose wrapper content omits $CORE_SCRIPT (scripts) or {CORE_TEMPLATE} (markdown/command templates); encountered during template layer merging.
Common situations: Copy-pasting a non-wrap template into a wrap layer; renaming or removing the placeholder while restyling a wrapper; using {CORE_TEMPLATE} in a script file (or $CORE_SCRIPT in markdown) so the type-specific placeholder is missing.
Related errors
- Each entry in 'provides.{section}' must be a mapping
- Invalid {singular} entry '{name}': 'strategy' is not authora
- Invalid YAML in {path}: {e}
- specify event ${{command}} (${{event}}) failed: ${{(e as Err
- errors.join('; ')
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/2a639a3f6db5098c.
Report an issue: GitHub.