github/spec-kit · error · PresetValidationError

Invalid strategy '{strategy}': must be one of {sorted(VALID_

Error message

Invalid strategy '{strategy}': must be one of {sorted(VALID_PRESET_STRATEGIES)}

What it means

The template's 'strategy' string is not one of the supported merge strategies. Valid values are {"replace", "prepend", "append", "wrap"} (compared case-insensitively — the value is lowercased before the check, and the normalized value is written back into the entry). The error message lists the exact accepted set.

Source

Thrown at src/specify_cli/presets/__init__.py:462

            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)}"
                )

            # 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:

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Change the template's strategy in preset.yml to one of: replace, prepend, append, wrap.
  2. If you wanted to fully overwrite the target file, use "replace" (the default — you can omit the key).
  3. Check the error message's sorted list; it reflects the exact VALID_PRESET_STRATEGIES set for your installed spec-kit version.

Example fix

# before
    strategy: merge

# after
    strategy: "replace"
Defensive patterns

Strategy: validation

Validate before calling

VALID = {"replace", "prepend", "append", "wrap"}
for t in yaml.safe_load(open("preset.yml")).get("templates", []):
    s = str(t.get("strategy", "replace")).lower()
    if s not in VALID:
        raise SystemExit(f"bad strategy {s!r}; allowed: {sorted(VALID)}")

Type guard

def is_valid_strategy(value) -> bool:
    return isinstance(value, str) and value.lower() in {"replace", "prepend", "append", "wrap"}

Try / catch

try:
    manager.install_from_directory(src, version)
except PresetValidationError as e:
    if "Invalid strategy" in str(e):
        print(e)  # message lists the exact allowed set for this spec-kit version

Prevention

When it happens

Trigger: Calling preset install (or PresetManifest validation) with a preset.yml template entry like `strategy: merge`, `strategy: overwrite`, or a typo such as `strategy: apend`. Any string outside {append, prepend, replace, wrap} after lowercasing triggers it.

Common situations: Porting a preset from another tool whose strategy vocabulary differs (merge/overwrite), typos, or docs from an older/newer spec-kit version that supports a different strategy set.

Related errors


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/821c001ec56472fb. Report an issue: GitHub.