{"record":{"id":"548611a48e348d61","repo":"github/spec-kit","slug":"catalog-entry-entry-id-verified-must-be-a-b","errorCode":null,"errorMessage":"Catalog entry '{entry_id}': 'verified' must be a boolean (true/false).","messagePattern":"Catalog entry '(.+?)': 'verified' must be a boolean \\(true/false\\)\\.","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/bundler/models/catalog.py","lineNumber":131,"sourceCode":"    \"\"\"\n    if value is None:\n        return ()\n    if isinstance(value, (str, bytes)) or not isinstance(value, (list, tuple)):\n        raise BundlerError(\n            f\"Catalog entry '{entry_id}': 'tags' must be a list of strings.\"\n        )\n    return tuple(str(t) for t in value)\n\n\ndef _parse_verified(value: Any, entry_id: str) -> bool:\n    \"\"\"Validate a catalog entry's ``verified`` flag is a real boolean.\n\n    ``bool(\"false\")`` is truthy, so coercing arbitrary strings would silently\n    mark untrusted entries as verified; require an actual boolean instead.\n    \"\"\"\n    if isinstance(value, bool):\n        return value\n    raise BundlerError(\n        f\"Catalog entry '{entry_id}': 'verified' must be a boolean (true/false).\"\n    )\n\n\n@dataclass(frozen=True)\nclass CatalogEntry:\n    id: str\n    name: str\n    version: str\n    role: str\n    description: str\n    author: str\n    license: str\n    download_url: str\n    requires_speckit_version: str\n    sha256: str | None = None\n    provides: dict[str, int] = field(default_factory=dict)\n    repository: str | None = None","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/bundler/models/catalog.py#L113-L149","documentation":"Raised by _parse_verified() when a catalog entry's 'verified' flag is not an actual JSON boolean. Because bool('false') is truthy in Python, stringly-typed values would silently mark untrusted entries as verified, so only true booleans are accepted; anything else (including the strings 'true'/'false') is rejected.","triggerScenarios":"A remote catalog entry with \"verified\": \"true\" (quoted string); verified: 1 or \"yes\" in YAML; a catalog producer serializing booleans through a template engine that quotes everything.","commonSituations":"Template-generated catalogs (Jinja, mustache) that render booleans as strings; YAML configs using yes/no which some loaders coerce unpredictably; third-party catalogs authored in JSON-by-hand.","solutions":["Fix the catalog payload to use unquoted JSON booleans: \"verified\": true or false.","Fix the catalog generator to use a real JSON serializer (json.dumps) rather than string templating.","If the flag is unknown, omit it — absent defaults to False, which is the safe direction."],"exampleFix":"# before (catalog JSON)\n\"verified\": \"true\"\n\n# after (catalog JSON)\n\"verified\": true","handlingStrategy":"type-guard","validationCode":"verified = entry.get(\"verified\")\nif verified is not None and not isinstance(verified, bool):\n    raise ValueError(f\"verified must be a boolean, got {type(verified).__name__}\")","typeGuard":"def is_valid_verified(value: object) -> bool:\n    return value is None or isinstance(value, bool)","tryCatchPattern":"try:\n    CatalogEntry.from_dict(entry_raw)\nexcept BundlerError as e:\n    if \"'verified' must be a boolean\" in str(e):\n        entry_raw.pop(\"verified\", None)  # absent defaults to False (safe)","preventionTips":["Never template booleans as strings; use json.dumps for catalog generation.","Omit 'verified' when unsure — the default False is the safe direction.","Remember bool('false') is truthy in Python: never coerce strings to bool."],"tags":["bundler","catalog","validation","verified","untrusted-input"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}