{"record":{"id":"bb6d26e985f95480","repo":"github/spec-kit","slug":"invalid-catalog-entry-at-index-idx-expected-a-m","errorCode":null,"errorMessage":"Invalid catalog entry at index {idx}: expected a mapping, got {type(item).__name__}","messagePattern":"Invalid catalog entry at index (.+?): expected a mapping, got (.+?)","errorType":"validation","errorClass":"PresetValidationError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/presets/__init__.py","lineNumber":4296,"sourceCode":"        except (yaml.YAMLError, OSError, UnicodeError) as e:\n            raise PresetValidationError(\n                f\"Failed to read catalog config {config_path}: {e}\"\n            )\n        if not isinstance(data, dict):\n            raise PresetValidationError(\n                f\"Invalid catalog config {config_path}: expected a mapping at root, got {type(data).__name__}\"\n            )\n        catalogs_data = data.get(\"catalogs\", [])\n        if not catalogs_data:\n            return None\n        if not isinstance(catalogs_data, list):\n            raise PresetValidationError(\n                f\"Invalid catalog config: 'catalogs' must be a list, got {type(catalogs_data).__name__}\"\n            )\n        entries: List[PresetCatalogEntry] = []\n        for idx, item in enumerate(catalogs_data):\n            if not isinstance(item, dict):\n                raise PresetValidationError(\n                    f\"Invalid catalog entry at index {idx}: expected a mapping, got {type(item).__name__}\"\n                )\n            url = str(item.get(\"url\", \"\")).strip()\n            if not url:\n                continue\n            self._validate_catalog_url(url)\n            raw_priority = item.get(\"priority\", idx + 1)\n            # Reject bools explicitly: ``bool`` is a subclass of ``int`` so\n            # ``int(True)`` silently returns 1, which would let a YAML\n            # ``priority: true`` slip through as a valid priority of 1. The\n            # sibling integration-catalog reader in ``catalogs.py`` already\n            # guards this; mirror the check here so the three catalog\n            # validators stay consistent.\n            if isinstance(raw_priority, bool):\n                raise PresetValidationError(\n                    f\"Invalid priority for catalog '{item.get('name', idx + 1)}': \"\n                    f\"expected integer, got {raw_priority!r}\"\n                )","sourceCodeStart":4278,"sourceCodeEnd":4314,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/presets/__init__.py#L4278-L4314","documentation":"One element of the 'catalogs' list is not a mapping. Each catalog entry must be a dict with keys like url/name/priority/install_allowed; a string, number, or None element raises PresetValidationError with the offending index.","triggerScenarios":"A catalogs list containing a bare string ('catalogs: [https://example.com]') or a null element; any element parsed as a scalar instead of a mapping.","commonSituations":"Flow-style lists of URL strings instead of list-of-maps; a dash followed by nothing (empty entry) in the block sequence; copy-paste leaving a stray scalar between entries.","solutions":["Find the element at the reported index and convert it to a mapping: '- url: <value>'","Remove empty or placeholder entries from the catalogs list","Ensure every entry is '- key: value' block form, not a bare quoted string"],"exampleFix":"# before\ncatalogs:\n  - https://example.com/catalog.json\n\n# after\ncatalogs:\n  - url: https://example.com/catalog.json","handlingStrategy":"type-guard","validationCode":"for i, item in enumerate(data[\"catalogs\"]):\n    if not isinstance(item, dict):\n        raise ValueError(f\"catalog entry {i} must be a mapping\")","typeGuard":"def is_catalog_entry_list(items: object) -> bool:\n    return isinstance(items, list) and all(isinstance(x, dict) for x in items)","tryCatchPattern":"except PresetValidationError as e:\n    if \"expected a mapping\" in str(e):\n        # parse index from message, convert bare strings to {'url': s}\n        ...","preventionTips":["Never put bare URL strings in the catalogs list; always '- url: ...'","Validate each entry is a mapping before calling the loader"],"tags":["yaml","config","validation","type-mismatch"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}