BerriAI/litellm · warning · ValueError
RSS feed missing <channel> element
Error message
RSS feed missing <channel> element
What it means
Raised by get_blog_posts.py when parsing the LiteLLM blog RSS feed: the XML parsed successfully but has no <channel> element, so no <item> posts can be extracted. This is an internal utility (used for the 'what's new' blog lookup), not part of the completion API.
Source
Thrown at litellm/litellm_core_utils/get_blog_posts.py:78
Fetch RSS XML from a remote URL.
Returns the raw XML text. Raises on network errors.
"""
response: Final = httpx.get(url, timeout=timeout)
response.raise_for_status()
return response.text
@staticmethod
def parse_rss_to_posts(xml_text: str, max_posts: int = 1) -> list[dict[str, str]]:
"""
Parse RSS XML and return a list of blog post dicts.
Extracts title, description, date (YYYY-MM-DD), and url from each <item>.
"""
root: Final = ET.fromstring(xml_text)
channel: Final = root.find("channel")
if channel is None:
raise ValueError("RSS feed missing <channel> element")
posts: Final[list[dict[str, str]]] = []
for item in channel.findall("item"):
if len(posts) >= max_posts:
break
title_el = item.find("title")
link_el = item.find("link")
desc_el = item.find("description")
pub_date_el = item.find("pubDate")
if title_el is None or link_el is None:
continue
# Parse RFC 2822 date to YYYY-MM-DD
date_str = ""
if pub_date_el is not None and pub_date_el.text:
try:View on GitHub (pinned to 6c2dcb801b)
Solutions
- Verify the feed URL manually with curl and inspect the root element.
- If the upstream feed changed format, update the parser (support Atom <feed> or the new location) or pin to the last known-good URL.
- For tests, make the fixture include <rss><channel><item>...</item></channel></rss>.
Example fix
# before
posts = parse_rss_to_posts('<rss></rss>')
# after
posts = parse_rss_to_posts('<rss><channel><item><title>t</title><link>l</link></item></channel></rss>') Defensive patterns
Strategy: validation
Validate before calling
import xml.etree.ElementTree as ET
def has_channel(xml_text: str) -> bool:
try:
return ET.fromstring(xml_text).find('channel') is not None
except ET.ParseError:
return False Try / catch
try {
parseRssToPosts(xml);
} catch (e) {
if (/missing <channel>/.test(e.message)) { /* skip update, use cached posts */ }
} Prevention
- Validate feed shape (root rss + channel) before parsing.
- Cache last-good posts as a fallback display source.
- Monitor the feed URL for format changes.
When it happens
Trigger: Calling get_blog_posts / parse_rss_to_posts when the fetched URL returns XML that is valid but not RSS 2.0 — e.g. an HTML page, an Atom feed, an error page wrapped in XML, or a feed format change.
Common situations: The blog endpoint moved or changed format, a proxy/CDN returning an XML error document, or tests feeding fixture XML without a channel element.
Related errors
- Failed to parse tool call arguments. Error: {original_error}
- Error parsing chunk: {e}, Received chunk: {chunk}
- error_message or raw_response.text
- Failed to parse DashScope response as JSON: {e}
- Unexpected part type: {part}
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/8430eed166b0f799.
Report an issue: GitHub.