{"record":{"id":"20f006fa39ac1562","repo":"github/spec-kit","slug":"no-runnable-script-variant-for-this-platform-requ","errorCode":null,"errorMessage":"No runnable script variant for this platform: requested {requested!r}; available: {available}","messagePattern":"No runnable script variant for this platform: requested (.+?); available: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/integrations/base.py","lineNumber":731,"sourceCode":"        \"\"\"Select the requested variant or a runnable platform fallback.\"\"\"\n        if isinstance(requested, str) and requested in script_commands:\n            return requested\n\n        platform_variant = (\n            \"ps\" if platform.system().lower().startswith(\"win\") else \"sh\"\n        )\n        secondary_variant = \"sh\" if platform_variant == \"ps\" else \"ps\"\n        fallbacks = (\n            (platform_variant, \"py\")\n            if requested == \"py\"\n            else (platform_variant, secondary_variant, \"py\")\n        )\n        for candidate in fallbacks:\n            if candidate in script_commands:\n                return candidate\n\n        available = \", \".join(sorted(script_commands)) or \"none\"\n        raise ValueError(\n            \"No runnable script variant for this platform: \"\n            f\"requested {requested!r}; available: {available}\"\n        )\n\n    @staticmethod\n    def _interpreter_runs(path: str) -> bool:\n        \"\"\"Return True when *path* executes as a Python interpreter.\n\n        Runs isolated (``-I``) without ``site`` (``-S``) and discards\n        I/O so the probe is a fast liveness check that cannot trigger\n        ``sitecustomize``/user startup hooks.\n        \"\"\"\n        try:\n            return (\n                subprocess.run(\n                    [path, \"-I\", \"-S\", \"-c\", \"\"],\n                    stdin=subprocess.DEVNULL,\n                    stdout=subprocess.DEVNULL,","sourceCodeStart":713,"sourceCodeEnd":749,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/integrations/base.py#L713-L749","documentation":"IntegrationBase.select_script_variant picks the script variant (sh/ps/py) for a command template. It first honors the requested variant if present in script_commands (the variants the template's scripts: frontmatter actually provides); otherwise it falls back to the platform native variant (ps on Windows, sh elsewhere), then the cross-platform py, and only then gives up with this error. Seeing it means script_commands contained none of the viable candidates — i.e. the template declared no (or only the wrong) script variants.","triggerScenarios":"A command template whose scripts: frontmatter is missing or lists no sh/ps/py entries that match the platform fallbacks — e.g. only a 'ps' entry while running on Linux is fine (secondary fallback), but an empty or typo'd variant key set ('shell', 'bash') yields an empty/foreign script_commands dict; requesting a variant like 'py' when the template provides only variants outside the fallback chain.","commonSituations":"Custom or forked command templates that omit the scripts: frontmatter required by the parity rule; templates that use non-canonical keys; a template intentionally having no script (constitution/specify style) being processed through a path that expects one.","solutions":["Add a complete scripts: frontmatter to the template with sh, ps, and py entries (all three are required by the parity rule).","Check the reported 'available:' list — it shows exactly which variant keys the template did declare; fix typos like 'bash' -> 'sh'.","If the template genuinely needs no script, route it through the template path that skips select_script_variant instead of calling it unconditionally."],"exampleFix":"# before (templates/commands/my-command.md)\n---\ndescription: \"Broken\"\n---\n# after\n---\ndescription: \"Fixed\"\nscripts:\n  sh: scripts/bash/my-command.sh\n  ps: scripts/powershell/my-command.ps1\n  py: scripts/python/my_command.py\n---","handlingStrategy":"validation","validationCode":"from specify_cli.integrations.base import IntegrationBase\n\nvariant = IntegrationBase.select_script_variant(\n    requested, {k: v for k, v in script_commands.items()}\n)  # raises with the 'available:' list if unsatisfiable — call it early to fail fast","typeGuard":"def has_runnable_variant(script_commands: dict[str, str]) -> bool:\n    import platform\n    native = \"ps\" if platform.system().lower().startswith(\"win\") else \"sh\"\n    secondary = \"sh\" if native == \"ps\" else \"ps\"\n    return bool(script_commands) and any(\n        v in script_commands for v in (native, secondary, \"py\")\n    )","tryCatchPattern":"try:\n    variant = IntegrationBase.select_script_variant(requested, script_commands)\nexcept ValueError as exc:\n    raise SystemExit(\n        f\"template provides no runnable script variants ({exc}); \"\n        \"add sh/ps/py entries to its scripts: frontmatter\"\n    ) from None","preventionTips":["Always author command templates with the full scripts: frontmatter (sh, ps, py).","Keep the three script variants behaviorally identical per the parity rule so any fallback works.","Validate templates in CI: every template that invokes a script must declare all three variants."],"tags":["configuration","templates","scripts","cross-platform"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}