github/spec-kit · error · PresetValidationError
Invalid strategy value: must be a string, got {type(strategy
Error message
Invalid strategy value: must be a string, got {type(strategy).__name__} What it means
Raised while validating a template entry in preset.yml: the optional 'strategy' field on a template must be a YAML string (e.g. replace, prepend, append, wrap), but some other YAML type was found. The validator reports the offending Python type name so you can see whether YAML parsed your value as an int, bool, list, or dict. It is thrown before any strategy comparison, so nothing is installed.
Source
Thrown at src/specify_cli/presets/__init__.py:453
if tmpl["type"] not in VALID_PRESET_TEMPLATE_TYPES:
raise PresetValidationError(
f"Invalid template type '{tmpl['type']}': "
f"must be one of {sorted(VALID_PRESET_TEMPLATE_TYPES)}"
)
# Validate file path safety: must be relative, no parent traversal
file_path = tmpl["file"]
normalized = os.path.normpath(file_path)
if os.path.isabs(normalized) or normalized.startswith(".."):
raise PresetValidationError(
f"Invalid template file path '{file_path}': "
"must be a relative path within the preset directory"
)
# 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)}"
)
View on GitHub (pinned to bf88c9f9a8)
Solutions
- Open preset.yml and set the template's strategy to a quoted string: `strategy: "replace"` (valid values: append, prepend, replace, wrap).
- If the strategy is optional for your case, delete the key entirely — it defaults to "replace".
- If you generate preset.yml with yaml.safe_dump, ensure you pass a str value, not a bool/int/list.
Example fix
# before (preset.yml)
templates:
- name: build
type: script
file: scripts/build.sh
strategy: true # YAML bool
# after
strategy: "replace" Defensive patterns
Strategy: type-guard
Validate before calling
import yaml
m = yaml.safe_load(open("preset.yml"))
for t in m.get("templates", []):
s = t.get("strategy", "replace")
assert isinstance(s, str), f"template {t.get('name')}: strategy must be a string, got {type(s).__name__}" Type guard
def is_valid_strategy_type(value) -> bool:
return isinstance(value, str) Try / catch
try:
manager.install_from_directory(src, version)
except PresetValidationError as e:
if "Invalid strategy value" in str(e):
# fix preset.yml strategy field, re-run
... Prevention
- Always quote strategy values in YAML: strategy: "replace".
- Never use YAML bare yes/no/true/false as a strategy.
- Lint preset.yml in CI before publishing the preset.
When it happens
Trigger: A template entry in preset.yml whose 'strategy' key is a non-string YAML scalar or collection, e.g. `strategy: [replace]` (list), `strategy: {name: replace}` (dict), `strategy: 10` (int), or `strategy: true` (bool). YAML booleans are a frequent trap: an unquoted value is parsed by YAML into a bool/int, not a string.
Common situations: Hand-editing preset.yml and writing `strategy: yes`/`strategy: no` (parsed as bool), copying a JSON-style array from docs, or generating the manifest programmatically and inserting a Python object instead of a str.
Related errors
- Invalid strategy '{strategy}': must be one of {sorted(VALID_
- Invalid strategy '{strategy}' for script: scripts only suppo
- Failed to parse extension registry {registry}: {exc}
- Failed to parse preset manifest {manifest_path}: {exc}
- Unknown template composition strategy '{strategy}' in {path}
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/ae30ba018a6ed275.
Report an issue: GitHub.