{"record":{"id":"44f26b452d76ab5b","repo":"ZhuLinsen/daily_stock_analysis","slug":"unsupported-feed-format-expected-rss-or-atom","errorCode":null,"errorMessage":"unsupported feed format; expected RSS or Atom","messagePattern":"unsupported feed format; expected RSS or Atom","errorType":"exception","errorClass":"IntelligenceServiceError","httpStatus":400,"severity":"warning","filePath":"src/services/intelligence_service.py","lineNumber":608,"sourceCode":"                ip = ipaddress.ip_address(info[4][0])\n            except (IndexError, TypeError, ValueError):\n                continue\n            if IntelligenceService._is_blocked_ip(ip):\n                raise IntelligenceServiceError(\"source url must not target private or local network addresses\")\n\n    def _parse_feed(self, content: bytes, *, source_name: str, limit: int) -> List[FeedEntry]:\n        try:\n            root = ET.fromstring(content)\n        except ET.ParseError as exc:\n            raise IntelligenceServiceError(f\"invalid RSS/Atom feed: {exc}\") from exc\n        tag = self._strip_ns(root.tag).lower()\n        if tag == \"rss\":\n            nodes = root.findall(\"./channel/item\")\n            return [entry for entry in (self._parse_rss_item(node, source_name) for node in nodes[:limit]) if entry]\n        if tag == \"feed\":\n            nodes = root.findall(\"./{*}entry\") or root.findall(\"./entry\")\n            return [entry for entry in (self._parse_atom_entry(node, source_name) for node in nodes[:limit]) if entry]\n        raise IntelligenceServiceError(\"unsupported feed format; expected RSS or Atom\")\n\n    def _parse_newsnow_payload(self, payload: Any, *, source_name: str, limit: int) -> List[FeedEntry]:\n        if not isinstance(payload, dict):\n            raise IntelligenceServiceError(\"invalid NewsNow response: expected object\")\n        items = payload.get(\"items\")\n        if not isinstance(items, list):\n            raise IntelligenceServiceError(\"invalid NewsNow response: missing items\")\n        entries = []\n        for item in items[:limit]:\n            if not isinstance(item, dict):\n                continue\n            extra = item.get(\"extra\") if isinstance(item.get(\"extra\"), dict) else {}\n            published_raw = item.get(\"pubDate\") or extra.get(\"date\")\n            entries.append(self._build_entry(\n                str(item.get(\"title\") or \"\"),\n                str(extra.get(\"info\") or extra.get(\"hover\") or \"\"),\n                str(item.get(\"url\") or item.get(\"mobileUrl\") or \"\"),\n                source_name,","sourceCodeStart":590,"sourceCodeEnd":626,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/services/intelligence_service.py#L590-L626","documentation":"IntelligenceServiceError('unsupported feed format; expected RSS or Atom') is raised by _parse_feed when the body parses as valid XML but the root element (namespace-stripped, lowercased) is neither 'rss' nor 'feed'. The service deliberately supports only RSS (<rss><channel><item>) and Atom (<feed><entry>) shapes.","triggerScenarios":"Feeding a generic XML document (e.g. RDF/Sitemap.xml, OPML, an RSS 1.0 RDF variant whose root is <rdf:RDF>), a JSON payload misconfigured with a feed-type source, or any well-formed XML whose root tag is not rss/feed.","commonSituations":"Configuring a sitemap or news-sitemap URL as a feed source, an RSS 1.0 (RDF) endpoint, a source that switched its feed technology (e.g. to JSON-only), or a copy-paste mistake putting an article URL instead of the feed URL.","solutions":["Inspect the root element: curl -sL <url> | head -c 200 and confirm it starts with <rss or <feed","If it is RSS 1.0/RDF, find the provider's RSS 2.0 or Atom endpoint instead","If the source only emits JSON, use the NewsNow/JSON source type this service already supports rather than the RSS path","Update the source entry in configuration to the correct feed URL"],"exampleFix":"# before: sitemap mistakenly configured as a feed\nurl = \"https://example.com/sitemap.xml\"\n\n# after: real Atom feed\nurl = \"https://example.com/feeds/atom.xml\"","handlingStrategy":"validation","validationCode":"import xml.etree.ElementTree as ET\n\ndef root_is_rss_or_atom(content: bytes) -> bool:\n    try:\n        tag = ET.fromstring(content).tag.split('}')[-1].lower()\n    except ET.ParseError:\n        return False\n    return tag in {\"rss\", \"feed\"}","typeGuard":null,"tryCatchPattern":"try:\n    entries = svc._parse_feed(content, source_name=src, limit=20)\nexcept IntelligenceServiceError as exc:\n    if \"unsupported feed format\" in str(exc):\n        logger.warning(\"%s is not RSS/Atom; find the correct feed URL\", src)","preventionTips":["Verify the root element is <rss> or <feed> when registering a new source","Do not reuse sitemap/OPML/RDF URLs as feed sources","Use JSON/NewsNow source type for JSON-only providers"],"tags":["feed","xml","parsing","configuration"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}