github/spec-kit · error · PresetValidationError
Invalid strategy '{strategy}' for script: scripts only suppo
Error message
Invalid strategy '{strategy}' for script: scripts only support {sorted(VALID_SCRIPT_STRATEGIES)} What it means
A stricter, script-specific strategy check: entries with `type: script` only support {"replace", "wrap"}. Prepending or appending to an executable script does not make sense semantically, so it is rejected even though those strategies are valid for other template types.
Source
Thrown at src/specify_cli/presets/__init__.py:467
# Validate strategy field (optional, defaults to "replace")
strategy = tmpl.get("strategy", "replace")
if not isinstance(strategy, str):
raise PresetValidationError(
f"Invalid strategy value: must be a string, "
f"got {type(strategy).__name__}"
)
strategy = strategy.lower()
# Persist normalized value so downstream code sees lowercase
if "strategy" in tmpl:
tmpl["strategy"] = strategy
if strategy not in VALID_PRESET_STRATEGIES:
raise PresetValidationError(
f"Invalid strategy '{strategy}': "
f"must be one of {sorted(VALID_PRESET_STRATEGIES)}"
)
if tmpl["type"] == "script" and strategy not in VALID_SCRIPT_STRATEGIES:
raise PresetValidationError(
f"Invalid strategy '{strategy}' for script: "
f"scripts only support {sorted(VALID_SCRIPT_STRATEGIES)}"
)
# Validate template name format
if tmpl["type"] == "command":
# Commands use dot notation (e.g. speckit.specify)
if not re.match(r'^[a-z0-9.-]+$', tmpl["name"]):
raise PresetValidationError(
f"Invalid command name '{tmpl['name']}': "
"must be lowercase alphanumeric with hyphens and dots only"
)
else:
if not re.match(r'^[a-z0-9-]+$', tmpl["name"]):
raise PresetValidationError(
f"Invalid template name '{tmpl['name']}': "
"must be lowercase alphanumeric with hyphens only"
)View on GitHub (pinned to bf88c9f9a8)
Solutions
- Set the script template's strategy to "replace" or "wrap".
- If you actually need prepend/append behavior, the entry is not a script — reconsider its type or restructure so the script itself composes content.
- Omit strategy for scripts wanting full overwrite — default is "replace".
Example fix
# before
- name: setup
type: script
file: scripts/setup.sh
strategy: append
# after
strategy: "replace" Defensive patterns
Strategy: validation
Validate before calling
SCRIPT_OK = {"replace", "wrap"}
for t in yaml.safe_load(open("preset.yml")).get("templates", []):
if t.get("type") == "script":
s = str(t.get("strategy", "replace")).lower()
assert s in SCRIPT_OK, f"script {t.get('name')}: strategy must be replace or wrap, got {s!r}" Type guard
def script_strategy_ok(template: dict) -> bool:
return str(template.get("strategy", "replace")).lower() in {"replace", "wrap"} Try / catch
try:
manager.install_from_directory(src, version)
except PresetValidationError as e:
if "for script" in str(e):
# script templates only accept replace/wrap; fix and retry
... Prevention
- Scripts only support replace and wrap — prepend/append are content-merge strategies.
- When copying a command entry and changing type to script, drop or change the strategy.
When it happens
Trigger: preset.yml contains a template with `type: script` and `strategy: prepend` or `strategy: append`. The general strategy check (VALID_PRESET_STRATEGIES) passes first, then this script-specific check fails.
Common situations: Copying a command template entry (which supports prepend/append for content merging) and changing only its type to script, or assuming one uniform strategy vocabulary across all template types.
Related errors
- Invalid strategy value: must be a string, got {type(strategy
- Invalid strategy '{strategy}': must be one of {sorted(VALID_
- Unknown template composition strategy '{strategy}' in {path}
- Invalid command name '{tmpl['name']}': must be lowercase alp
- Invalid template name '{tmpl['name']}': must be lowercase al
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/1f89f5c3cd47439a.
Report an issue: GitHub.