ZhuLinsen/daily_stock_analysis · warning · IntelligenceServiceError
invalid RSS/Atom feed: {exc}
Error message
invalid RSS/Atom feed: {exc} What it means
IntelligenceServiceError('invalid RSS/Atom feed: {exc}') is raised by _parse_feed when xml.etree.ElementTree.fromstring fails with ET.ParseError on the downloaded feed body. The message embeds the underlying parser message (e.g. 'syntax error', 'mismatched tag', 'not well-formed (invalid token)'). It means the bytes handed to the XML parser were not well-formed XML.
Source
Thrown at src/services/intelligence_service.py:600
return normalized.encode("idna").decode("ascii")
except UnicodeError:
return normalized
@staticmethod
def _validate_addrinfos(addr_infos: Any) -> None:
for info in addr_infos or []:
try:
ip = ipaddress.ip_address(info[4][0])
except (IndexError, TypeError, ValueError):
continue
if IntelligenceService._is_blocked_ip(ip):
raise IntelligenceServiceError("source url must not target private or local network addresses")
def _parse_feed(self, content: bytes, *, source_name: str, limit: int) -> List[FeedEntry]:
try:
root = ET.fromstring(content)
except ET.ParseError as exc:
raise IntelligenceServiceError(f"invalid RSS/Atom feed: {exc}") from exc
tag = self._strip_ns(root.tag).lower()
if tag == "rss":
nodes = root.findall("./channel/item")
return [entry for entry in (self._parse_rss_item(node, source_name) for node in nodes[:limit]) if entry]
if tag == "feed":
nodes = root.findall("./{*}entry") or root.findall("./entry")
return [entry for entry in (self._parse_atom_entry(node, source_name) for node in nodes[:limit]) if entry]
raise IntelligenceServiceError("unsupported feed format; expected RSS or Atom")
def _parse_newsnow_payload(self, payload: Any, *, source_name: str, limit: int) -> List[FeedEntry]:
if not isinstance(payload, dict):
raise IntelligenceServiceError("invalid NewsNow response: expected object")
items = payload.get("items")
if not isinstance(items, list):
raise IntelligenceServiceError("invalid NewsNow response: missing items")
entries = []
for item in items[:limit]:
if not isinstance(item, dict):View on GitHub (pinned to 5159bd72e8)
Solutions
- Fetch the URL manually and inspect the first bytes: curl -sL <url> | head -c 400 — HTML output means the URL/auth is wrong, not the parser
- If the body is HTML, fix the source configuration (real feed URL, required headers, or cookies)
- If the body is XML but malformed, report it upstream or switch to the provider's valid feed endpoint
- Validate encoding: ensure the response is decoded per its declared charset before ET.fromstring
- Catch IntelligenceServiceError per source so one bad feed does not abort the whole refresh
Example fix
# before: URL actually serves an HTML portal page source = IntelligenceSource(name="news", url="https://example.com/news") # after: the real RSS endpoint source = IntelligenceSource(name="news", url="https://example.com/news/rss.xml")
Defensive patterns
Strategy: try-catch
Validate before calling
def looks_like_feed_xml(content: bytes) -> bool:
head = content.lstrip()[:256]
return head.startswith(b"<?xml") or b"<rss" in head or b"<feed" in head Try / catch
try:
entries = svc._parse_feed(content, source_name=src, limit=20)
except IntelligenceServiceError as exc:
if "invalid RSS/Atom feed" in str(exc):
logger.warning("source %s returned non-XML body; check auth/URL", src)
entries = [] # degrade per source Prevention
- Sniff the first bytes for '<?xml'/'<rss'/'<feed' before parsing
- Log a content preview (first 200 bytes) on parse failure to diagnose HTML error pages
- Monitor feed sources for auth expiry and bot-challenge pages
When it happens
Trigger: A feed URL returning HTML (login pages, Cloudflare challenges, 404 pages served with status 200), truncated bodies from proxies, feeds containing unescaped ampersands or invalid UTF-8, or a payload that exceeded some downstream truncation before parsing.
Common situations: Source behind authentication that redirects to an HTML login, CDN bot protection returning an interstitial, an RSS generator emitting unescaped entities, charset mismatch (GBK content declared as UTF-8), or a truncated response from an aggressive proxy.
Related errors
- unsupported feed format; expected RSS or Atom
- invalid NewsNow response: expected object
- read_failed
- internal_error
- {call_name} 调用超过 {wait_seconds:g}s,已放弃等待
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/f57a3cfff2c11874.
Report an issue: GitHub.