HKUDS/Vibe-Trading · error · RuntimeError

N-PORT document did not parse: {exc}

Error message

N-PORT document did not parse: {exc}

What it means

An individual N-PORT XML filing downloaded from EDGAR failed to parse with defusedxml, so it is treated as a malformed-filing data error. Usually the download was truncated or returned an HTML error page instead of the filing XML.

Source

Thrown at agent/src/tools/etf_holdings_tool.py:755


def _parse_nport(xml_text: str) -> dict[str, Any]:
    """Parse an N-PORT ``primary_doc.xml`` into fund metadata plus holdings.

    Args:
        xml_text: The raw filing document.

    Returns:
        ``{series_id, series_name, registrant, as_of, fiscal_year_end,
        total_assets_usd, net_assets_usd, holdings}``.

    Raises:
        RuntimeError: When the document is not parseable XML.
    """
    try:
        root = DefusedET.fromstring(xml_text.encode("utf-8", "replace"))
    except Exception as exc:  # noqa: BLE001 - a malformed filing is a data error
        raise RuntimeError(f"N-PORT document did not parse: {exc}") from exc

    form_data = _child(root, "formData")
    gen_info = _child(form_data, "genInfo")
    fund_info = _child(form_data, "fundInfo")
    securities = _child(form_data, "invstOrSecs")

    holdings = []
    if securities is not None:
        holdings = [
            _parse_nport_holding(node)
            for node in securities
            if _local_name(node.tag) == "invstOrSec"
        ]

    return {
        "series_id": _text_of(gen_info, "seriesId"),
        "series_name": _text_of(gen_info, "seriesName"),
        "registrant": _text_of(gen_info, "regName"),

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Retry the specific filing download after throttling; verify the document URL opens in a browser
  2. Check HTTP status and content-type before parsing, and skip+log filings that return HTML
  3. Use the most recent accession when amendments supersede older documents
Defensive patterns

Strategy: retry

Validate before calling

import xml.etree.ElementTree as ET

def is_valid_xml(text: str) -> bool:
    try:
        ET.fromstring(text.encode("utf-8", "replace"))
        return True
    except ET.ParseError:
        return False

Try / catch

try:
    holdings = _parse_nport(xml_text)
except RuntimeError as exc:
    if "did not parse" in str(exc):
        xml_text = refetch(cik, accession)  # re-download with throttle
        holdings = _parse_nport(xml_text)
    else:
        raise

Prevention

When it happens

Trigger: Downloading an N-PORT primary document that is incomplete/truncated, sec.gov returning an error page for the document URL, or an encoding-mangled body that fromstring rejects even after utf-8 replace.

Common situations: Intermittent network drops mid-download; SEC rate limiting document GETs in tight loops; stale accession-number URLs after filings are amended/removed.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/1000c1ed849fb6d4. Report an issue: GitHub.