{"record":{"id":"0068270fd690b078","repo":"github/spec-kit","slug":"catalog-entry-entry-id-or-unknown-requir","errorCode":null,"errorMessage":"Catalog entry '{entry_id or '<unknown>'}': 'requires' must be a mapping when present.","messagePattern":"Catalog entry '(.+?)': 'requires' must be a mapping when present\\.","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/bundler/models/catalog.py","lineNumber":168,"sourceCode":"    tags: tuple[str, ...] = ()\n    verified: bool = False\n    # Resolution provenance (filled in by the catalog stack at lookup time):\n    source_id: str | None = None\n    source_policy: InstallPolicy | None = None\n\n    @classmethod\n    def from_dict(cls, data: Any) -> \"CatalogEntry\":\n        if not isinstance(data, dict):\n            raise BundlerError(\"Each catalog entry must be a mapping.\")\n        entry_id = str(data.get(\"id\", \"\")).strip()\n        # `or {}` would coerce a FALSY non-mapping (0, '', False, []) to {} before\n        # the isinstance guard, silently accepting a corrupt catalog entry; only\n        # an absent/None value means \"not present\".\n        requires = data.get(\"requires\")\n        if requires is None:\n            requires = {}\n        elif not isinstance(requires, dict):\n            raise BundlerError(\n                f\"Catalog entry '{entry_id or '<unknown>'}': 'requires' must be a \"\n                \"mapping when present.\"\n            )\n        provides_raw = data.get(\"provides\")\n        if provides_raw is None:\n            provides_raw = {}\n        elif not isinstance(provides_raw, dict):\n            raise BundlerError(\n                f\"Catalog entry '{entry_id or '<unknown>'}': 'provides' must be a \"\n                \"mapping when present.\"\n            )\n        return cls(\n            id=entry_id,\n            name=str(data.get(\"name\", \"\")).strip(),\n            version=str(data.get(\"version\", \"\")).strip(),\n            role=str(data.get(\"role\", \"\")).strip(),\n            description=str(data.get(\"description\", \"\")).strip(),\n            author=str(data.get(\"author\", \"\")).strip(),","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/bundler/models/catalog.py#L150-L186","documentation":"Raised by CatalogEntry.from_dict() when an entry's 'requires' field is present but is not a mapping. 'requires' declares capability/version prerequisites as an object (e.g. {\"speckit\": \">=1.0\"}); the code deliberately avoids `or {}` because that would silently coerce falsy non-mappings (0, '', False, []) into 'no requirements', accepting a corrupt entry.","triggerScenarios":"A catalog entry with \"requires\": [\"speckit>=1.0\"] (list) or \"requires\": \">=1.0\" (string); requires: 0 or false in hand-written YAML; requires: null is fine (treated as absent), anything else raises.","commonSituations":"Catalog authors more comfortable with arrays writing dependency lists; converting a requirements.txt-style syntax into catalogs; schema drift between catalog versions.","solutions":["Express 'requires' as an object mapping requirement names to constraints: {\"speckit\": \">=1.0\"}.","If no requirements, omit the key or set it to null — do not use an empty string or false.","Check the catalog schema documentation for the expected mapping shape."],"exampleFix":"# before (catalog JSON)\n\"requires\": [\"speckit>=1.0\"]\n\n# after (catalog JSON)\n\"requires\": {\"speckit\": \">=1.0\"}","handlingStrategy":"type-guard","validationCode":"requires = entry.get(\"requires\")\nif requires is not None and not isinstance(requires, dict):\n    raise ValueError(\"'requires' must be a mapping when present\")","typeGuard":"def is_valid_requires(value: object) -> bool:\n    return value is None or isinstance(value, dict)","tryCatchPattern":"try:\n    CatalogEntry.from_dict(entry_raw)\nexcept BundlerError as e:\n    if \"'requires' must be a mapping\" in str(e):\n        entry_raw.pop(\"requires\", None)  # drop rather than trust a malformed constraint","preventionTips":["Write requires as {\"name\": \"constraint\"} objects, never lists or strings.","Omit requires when there are no prerequisites.","Validate published catalogs with a JSON schema before serving them."],"tags":["bundler","catalog","validation","requires","untrusted-input"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}