{"record":{"id":"02b098056869d535","repo":"github/spec-kit","slug":"preset-pack-id-has-no-download-url","errorCode":null,"errorMessage":"Preset '{pack_id}' has no download URL","messagePattern":"Preset '(.+?)' has no download URL","errorType":"exception","errorClass":"PresetError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/presets/__init__.py","lineNumber":4846,"sourceCode":"        if pack_info.get(\"bundled\") and not pack_info.get(\"download_url\"):\n            from ..extensions import REINSTALL_COMMAND\n            raise PresetError(\n                f\"Preset '{pack_id}' is bundled with spec-kit and has no download URL. \"\n                f\"It should be installed from the local package. \"\n                f\"Use 'specify preset add {pack_id}' to install from the bundled package, \"\n                f\"or reinstall spec-kit if the bundled files are missing: {REINSTALL_COMMAND}\"\n            )\n\n        if not pack_info.get(\"_install_allowed\", True):\n            catalog_name = pack_info.get(\"_catalog_name\", \"unknown\")\n            raise PresetError(\n                f\"Preset '{pack_id}' is from the '{catalog_name}' catalog which does not allow installation. \"\n                f\"Use --from with the preset's repository URL instead.\"\n            )\n\n        download_url = pack_info.get(\"download_url\")\n        if not download_url:\n            raise PresetError(\n                f\"Preset '{pack_id}' has no download URL\"\n            )\n        if not isinstance(download_url, str):\n            raise PresetError(\n                f\"Preset download URL is malformed: {download_url}\"\n            )\n\n        from urllib.parse import urlparse\n\n        # A malformed authority (e.g. an unterminated IPv6 bracket\n        # \"https://[::1\") makes urlparse / hostname access raise ValueError.\n        # The download_url comes from catalog payload data, so surface a clean\n        # PresetError rather than leaking a raw ValueError past the command\n        # handler (which only catches PresetError). Mirrors catalogs (#3435)\n        # and workflows/catalog.py (#3484).\n        try:\n            parsed = urlparse(download_url)\n            hostname = parsed.hostname","sourceCodeStart":4828,"sourceCodeEnd":4864,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/presets/__init__.py#L4828-L4864","documentation":"The pack's catalog entry has no download_url at all (falsy value). After the bundled and install_allowed checks, download cannot proceed without a URL, so PresetError is raised.","triggerScenarios":"A catalog entry that is not 'bundled' but omits download_url (or sets it to an empty string / null) — i.e. malformed third-party catalog data.","commonSituations":"Hand-authored catalog JSON missing the download_url field; catalog schema drift where the producer renamed the field; entry intentionally metadata-only being passed to the download path.","solutions":["Fix the catalog payload: add a valid HTTPS download_url to the pack entry","If the pack is meant to be local-only, mark it 'bundled' so callers take the local-install path","Report the broken entry to the catalog maintainer if you do not control it"],"exampleFix":"// before (catalog entry)\n{\"id\": \"mytheme\"}\n\n// after\n{\"id\": \"mytheme\", \"download_url\": \"https://example.com/mytheme-1.0.0.tar.gz\"}","handlingStrategy":"validation","validationCode":"info = manager.get_pack_info(pack_id) or {}\nif not info.get(\"download_url\") and not info.get(\"bundled\"):\n    raise ValueError(f\"catalog entry for {pack_id} lacks download_url\")","typeGuard":"def has_download_url(info: dict) -> bool:\n    return bool(info.get(\"download_url\")) or bool(info.get(\"bundled\"))","tryCatchPattern":"except PresetError as e:\n    if \"has no download URL\" in str(e):\n        # upstream catalog data defect; report rather than retry\n        report_catalog_defect(pack_id)\n    raise","preventionTips":["Schema-validate catalog payloads (download_url present and non-empty for non-bundled packs) before publishing","Treat a missing download_url as a data bug, not a transient failure — do not retry"],"tags":["presets","catalog","missing-field"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}