{"record":{"id":"aa907bc4c27eb168","repo":"microsoft/markitdown","slug":"no-channel-found-in-rss-feed","errorCode":null,"errorMessage":"No channel found in RSS feed","messagePattern":"No channel found in RSS feed","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"packages/markitdown/src/markitdown/converters/_rss_converter.py","lineNumber":141,"sourceCode":"            if entry_summary:\n                md_text += self._parse_content(entry_summary)\n            if entry_content:\n                md_text += self._parse_content(entry_content)\n\n        return DocumentConverterResult(\n            markdown=md_text,\n            title=title,\n        )\n\n    def _parse_rss_type(self, doc: Document) -> DocumentConverterResult:\n        \"\"\"Parse the type of an RSS feed.\n\n        Returns None if the feed type is not recognized or something goes wrong.\n        \"\"\"\n        root = doc.getElementsByTagName(\"rss\")[0]\n        channel_list = root.getElementsByTagName(\"channel\")\n        if not channel_list:\n            raise ValueError(\"No channel found in RSS feed\")\n        channel = channel_list[0]\n        channel_title = self._get_data_by_tag_name(channel, \"title\")\n        channel_description = self._get_data_by_tag_name(channel, \"description\")\n        items = channel.getElementsByTagName(\"item\")\n        if channel_title:\n            md_text = f\"# {channel_title}\\n\"\n        if channel_description:\n            md_text += f\"{channel_description}\\n\"\n        for item in items:\n            title = self._get_data_by_tag_name(item, \"title\")\n            description = self._get_data_by_tag_name(item, \"description\")\n            pubDate = self._get_data_by_tag_name(item, \"pubDate\")\n            content = self._get_data_by_tag_name(item, \"content:encoded\")\n\n            if title:\n                md_text += f\"\\n## {title}\\n\"\n            if pubDate:\n                md_text += f\"Published on: {pubDate}\\n\"","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/microsoft/markitdown/blob/fd239d5d2be43d9b68329730206b9312c7d5a388/packages/markitdown/src/markitdown/converters/_rss_converter.py#L123-L159","documentation":"After _feed_type() classified the document as RSS (an <rss> element exists), _parse_rss_type() requires at least one <channel> child element. An <rss> root with no <channel> raises ValueError('No channel found in RSS feed'). Per the RSS 2.0 spec a channel is mandatory, so this fires on truncated or malformed feeds that still have the <rss> wrapper.","triggerScenarios":"Converting XML whose root is <rss> (e.g. <rss version='2.0'></rss> or <rss> containing only non-channel elements) with zero <channel> descendants; feeds truncated mid-transfer so the channel opening tag was lost; empty template files with just the rss skeleton.","commonSituations":"Scraping a partially downloaded feed over a flaky connection; feeds behind error pages that still emit an <rss> root; hand-built test fixtures missing the channel block.","solutions":["Check the feed with a validator (e.g. w3.org feed validator) and confirm the <channel> element exists inside <rss>","Re-fetch the feed if it may have been truncated (verify Content-Length / try curl and inspect)","If you control the producer, emit a valid RSS 2.0 document with a channel containing title/link/description","Wrap conversion in a ValueError catch to skip malformed feeds in batch jobs"],"exampleFix":"# before\nresult = MarkItDown().convert('feed.rss')  # ValueError: No channel found in RSS feed\n\n# after: pre-check structure\nimport defusedxml.minidom as minidom\ndoc = minidom.parse('feed.rss')\nif not doc.getElementsByTagName('rss')[0].getElementsByTagName('channel'):\n    raise SkipFile('malformed rss: no channel')\nresult = MarkItDown().convert('feed.rss')","handlingStrategy":"validation","validationCode":"from defusedxml import minidom\n\ndef rss_has_channel(raw: bytes) -> bool:\n    try:\n        doc = minidom.parseString(raw)\n        rss = doc.getElementsByTagName(\"rss\")\n        return bool(rss) and bool(rss[0].getElementsByTagName(\"channel\"))\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    result = MarkItDown().convert(\"feed.rss\")\nexcept ValueError as e:\n    if \"No channel found\" in str(e):\n        logger.warning(\"malformed/truncated RSS feed; skipping\")  # skip in batch jobs","preventionTips":["Validate feeds (w3.org feed validator) before ingestion","Fetch feeds completely (check Content-Length / verify with curl) before converting","In batch pipelines, catch ValueError per feed and continue instead of aborting the run"],"tags":["rss","xml","feed","validation","malformed-input"],"backgroundTag":null,"analyzedSha":"fd239d5d2be43d9b68329730206b9312c7d5a388","analyzedAt":"2026-08-14T15:47:51.745Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}