{"record":{"id":"e561609ce9f37d79","repo":"github/spec-kit","slug":"catalog-entry-entry-id-or-unknown-provid","errorCode":null,"errorMessage":"Catalog entry '{entry_id or '<unknown>'}': 'provides' must be a mapping when present.","messagePattern":"Catalog entry '(.+?)': 'provides' must be a mapping when present\\.","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/bundler/models/catalog.py","lineNumber":176,"sourceCode":"        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(),\n            license=str(data.get(\"license\", \"\")).strip(),\n            download_url=str(data.get(\"download_url\", \"\")).strip(),\n            requires_speckit_version=str(requires.get(\"speckit_version\", \"\")).strip(),\n            sha256=(\n                None\n                if data.get(\"sha256\") is None\n                else str(data[\"sha256\"]).strip()\n            ),","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/bundler/models/catalog.py#L158-L194","documentation":"Raised by CatalogEntry.from_dict() when an entry's 'provides' field is present but is not a mapping. 'provides' declares capabilities the bundle supplies with integer weights (e.g. {\"lint\": 1}); the same no-`or {}` discipline as 'requires' applies so corrupt falsy values cannot masquerade as 'provides nothing'.","triggerScenarios":"A catalog entry with \"provides\": \"lint\" or \"provides\": [\"lint\"]; provides: 0 or false; provides: null is fine (treated as absent).","commonSituations":"Catalog authors writing provides as a tag list; schema drift; hand-edited catalogs approximating the format from memory.","solutions":["Express 'provides' as an object mapping capability names to integers: {\"lint\": 1}.","If the bundle provides nothing declared, omit the key or set null.","Align with the documented catalog schema before publishing."],"exampleFix":"# before (catalog JSON)\n\"provides\": [\"lint\"]\n\n# after (catalog JSON)\n\"provides\": {\"lint\": 1}","handlingStrategy":"type-guard","validationCode":"provides = entry.get(\"provides\")\nif provides is not None and not isinstance(provides, dict):\n    raise ValueError(\"'provides' must be a mapping when present\")","typeGuard":"def is_valid_provides(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 \"'provides' must be a mapping\" in str(e):\n        entry_raw.pop(\"provides\", None)  # drop malformed capability claims","preventionTips":["Write provides as {\"capability\": weight} objects with integer weights.","Omit provides when the bundle declares no capabilities.","Keep 'requires' and 'provides' shapes symmetric in docs and generators to avoid confusion."],"tags":["bundler","catalog","validation","provides","untrusted-input"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}