{"record":{"id":"821c001ec56472fb","repo":"github/spec-kit","slug":"invalid-strategy-strategy-must-be-one-of-sor","errorCode":null,"errorMessage":"Invalid strategy '{strategy}': must be one of {sorted(VALID_PRESET_STRATEGIES)}","messagePattern":"Invalid strategy '(.+?)': must be one of (.+?)","errorType":"validation","errorClass":"PresetValidationError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/presets/__init__.py","lineNumber":462,"sourceCode":"            if os.path.isabs(normalized) or normalized.startswith(\"..\"):\n                raise PresetValidationError(\n                    f\"Invalid template file path '{file_path}': \"\n                    \"must be a relative path within the preset directory\"\n                )\n\n            # Validate strategy field (optional, defaults to \"replace\")\n            strategy = tmpl.get(\"strategy\", \"replace\")\n            if not isinstance(strategy, str):\n                raise PresetValidationError(\n                    f\"Invalid strategy value: must be a string, \"\n                    f\"got {type(strategy).__name__}\"\n                )\n            strategy = strategy.lower()\n            # Persist normalized value so downstream code sees lowercase\n            if \"strategy\" in tmpl:\n                tmpl[\"strategy\"] = strategy\n            if strategy not in VALID_PRESET_STRATEGIES:\n                raise PresetValidationError(\n                    f\"Invalid strategy '{strategy}': \"\n                    f\"must be one of {sorted(VALID_PRESET_STRATEGIES)}\"\n                )\n            if tmpl[\"type\"] == \"script\" and strategy not in VALID_SCRIPT_STRATEGIES:\n                raise PresetValidationError(\n                    f\"Invalid strategy '{strategy}' for script: \"\n                    f\"scripts only support {sorted(VALID_SCRIPT_STRATEGIES)}\"\n                )\n\n            # Validate template name format\n            if tmpl[\"type\"] == \"command\":\n                # Commands use dot notation (e.g. speckit.specify)\n                if not re.match(r'^[a-z0-9.-]+$', tmpl[\"name\"]):\n                    raise PresetValidationError(\n                        f\"Invalid command name '{tmpl['name']}': \"\n                        \"must be lowercase alphanumeric with hyphens and dots only\"\n                    )\n            else:","sourceCodeStart":444,"sourceCodeEnd":480,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/presets/__init__.py#L444-L480","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Change the template's strategy in preset.yml to one of: replace, prepend, append, wrap.","If you wanted to fully overwrite the target file, use \"replace\" (the default — you can omit the key).","Check the error message's sorted list; it reflects the exact VALID_PRESET_STRATEGIES set for your installed spec-kit version."],"exampleFix":"# before\n    strategy: merge\n\n# after\n    strategy: \"replace\"","handlingStrategy":"validation","validationCode":"VALID = {\"replace\", \"prepend\", \"append\", \"wrap\"}\nfor t in yaml.safe_load(open(\"preset.yml\")).get(\"templates\", []):\n    s = str(t.get(\"strategy\", \"replace\")).lower()\n    if s not in VALID:\n        raise SystemExit(f\"bad strategy {s!r}; allowed: {sorted(VALID)}\")","typeGuard":"def is_valid_strategy(value) -> bool:\n    return isinstance(value, str) and value.lower() in {\"replace\", \"prepend\", \"append\", \"wrap\"}","tryCatchPattern":"try:\n    manager.install_from_directory(src, version)\nexcept PresetValidationError as e:\n    if \"Invalid strategy\" in str(e):\n        print(e)  # message lists the exact allowed set for this spec-kit version","preventionTips":["Remember the four strategies: replace, prepend, append, wrap (case-insensitive).","Omit strategy when you want the default replace behavior.","Cross-check against the error message's list, which reflects your installed version."],"tags":["preset","validation","strategy"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}