{"record":{"id":"71d84b5bce2e2e41","repo":"github/spec-kit","slug":"invalid-preset-catalog-format-from-url","errorCode":null,"errorMessage":"Invalid preset catalog format from {url}","messagePattern":"Invalid preset catalog format from (.+?)","errorType":"exception","errorClass":"PresetError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/presets/__init__.py","lineNumber":4253,"sourceCode":"\n        Args:\n            catalog_data: Parsed JSON payload from the catalog source.\n            url: Source URL — used in the error message so the user can\n                tell which catalog in a multi-catalog stack is malformed.\n\n        Raises:\n            PresetError: If the payload's shape is invalid.\n        \"\"\"\n        if not isinstance(catalog_data, dict):\n            raise PresetError(\n                f\"Invalid preset catalog format from {url}: \"\n                \"expected a JSON object\"\n            )\n        if (\n            \"schema_version\" not in catalog_data\n            or \"presets\" not in catalog_data\n        ):\n            raise PresetError(f\"Invalid preset catalog format from {url}\")\n        if not isinstance(catalog_data.get(\"presets\"), dict):\n            raise PresetError(\n                f\"Invalid preset catalog format from {url}: \"\n                \"'presets' must be a JSON object\"\n            )\n\n    def _load_catalog_config(self, config_path: Path) -> Optional[List[PresetCatalogEntry]]:\n        \"\"\"Load catalog stack configuration from a YAML file.\n\n        Args:\n            config_path: Path to preset-catalogs.yml\n\n        Returns:\n            Ordered list of PresetCatalogEntry objects, or None if file\n            doesn't exist or contains no valid catalog entries.\n\n        Raises:\n            PresetValidationError: If any catalog entry has an invalid URL,","sourceCodeStart":4235,"sourceCodeEnd":4271,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/presets/__init__.py#L4235-L4271","documentation":"The catalog JSON object is missing one or both required top-level keys: `schema_version` and `presets`. Both are mandatory; the catalog format version drives forward compatibility, so an object without them is treated as an invalid catalog. The URL is included to identify which stacked catalog is at fault.","triggerScenarios":"A catalog document like {\"presets\": {...}} (no schema_version), {\"schema_version\": 1} (no presets), or an unrelated JSON object entirely (e.g. a package.json) served at the catalog URL.","commonSituations":"Hand-authoring a catalog and forgetting schema_version, or pointing the URL at the wrong JSON file in the repo.","solutions":["Add both keys: `schema_version` (check existing public catalogs for the current value) and `presets` (an object keyed by preset id).","Model your catalog on a known-good one served by the spec-kit project.","Validate locally before publishing: both keys present, presets is an object."],"exampleFix":"# before\n{\n  \"presets\": { \"my-preset\": { ... } }\n}\n\n# after\n{\n  \"schema_version\": 1,\n  \"presets\": { \"my-preset\": { ... } }\n}","handlingStrategy":"validation","validationCode":"data = json.load(urllib.request.urlopen(url))\nassert \"schema_version\" in data and \"presets\" in data, \"catalog missing schema_version/presets\"","typeGuard":"def has_catalog_required_keys(payload: dict) -> bool:\n    return isinstance(payload, dict) and \"schema_version\" in payload and \"presets\" in payload","tryCatchPattern":"try:\n    manager.refresh_catalogs()\nexcept PresetError as e:\n    if \"Invalid preset catalog format\" in str(e):\n        # message names the URL; fix that catalog document's keys and retry\n        ...","preventionTips":["Both top-level keys are mandatory: schema_version and presets.","Model new catalogs on a known-good public spec-kit catalog.","Validate catalog JSON in the catalog repo's CI."],"tags":["preset","catalog","json","schema"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}