{"record":{"id":"5f704c48594ff7b3","repo":"Stirling-Tools/Stirling-PDF","slug":"failed-to-parse-path-exc","errorCode":null,"errorMessage":"Failed to parse {path}: {exc}","messagePattern":"Failed to parse (.+?): (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"scripts/coverage-summary.py","lineNumber":67,"sourceCode":"    def pct(self) -> float:\n        return 100.0 * self.covered / self.total if self.total else 0.0\n\n    def add(self, other: CounterTotals) -> None:\n        self.covered += other.covered\n        self.missed += other.missed\n\n\ndef _parse_jacoco_xml(path: Path) -> dict[str, CounterTotals]:\n    \"\"\"Read top-level <counter> elements from a JaCoCo report XML.\n\n    ElementTree's default parser doesn't validate the DTD, so JaCoCo's\n    `report.dtd` reference is harmless even on offline CI runners.\n    Counters are direct children of the <report> root.\n    \"\"\"\n    try:\n        root = _xml_parse(path).getroot()\n    except _XMLParseError as exc:\n        raise RuntimeError(f\"Failed to parse {path}: {exc}\") from exc\n\n    out: dict[str, CounterTotals] = {}\n    for counter in root.findall(\"counter\"):\n        t = counter.get(\"type\") or \"\"\n        if t not in JACOCO_COUNTERS:\n            continue\n        out[t] = CounterTotals(\n            covered=int(counter.get(\"covered\") or 0),\n            missed=int(counter.get(\"missed\") or 0),\n        )\n    return out\n\n\ndef _bar(pct: float, width: int = 20) -> str:\n    \"\"\"Render a fixed-width ASCII progress bar. Markdown-safe on all consoles.\"\"\"\n    filled = int(round(pct / 100.0 * width))\n    return \"[\" + \"#\" * filled + \"-\" * (width - filled) + \"]\"\n","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/scripts/coverage-summary.py#L49-L85","documentation":"RuntimeError raised when ElementTree fails to parse a JaCoCo XML coverage report file. The XML is malformed, truncated, or not valid XML, so _xml_parse raises a ParseError which is wrapped into this RuntimeError with the path and underlying exception.","triggerScenarios":"Running scripts/coverage-summary.py against a JaCoCo report XML that is empty, truncated, contains invalid characters, or is not well-formed XML.","commonSituations":"JaCoCo was killed mid-write, leaving a truncated report. A glob pattern matched a non-XML file or an empty placeholder. Encoding issues in the report.","solutions":["Validate the XML: xmllint <path> to see the parse error location.","Re-run the JaCoCo test/coverage generation to produce a complete report.","Ensure the path glob only matches fully-written JaCoCo report XML files."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"# Validate XML before parsing the report\nimport xml.dom.minidom as M\ntry:\n    M.parse(str(path))\nexcept Exception as e:\n    print(f\"Invalid XML {path}: {e}\", file=sys.stderr)","typeGuard":null,"tryCatchPattern":"try:\n    root = _xml_parse(path).getroot()\nexcept _XMLParseError as exc:\n    raise RuntimeError(f\"Failed to parse {path}: {exc}\") from exc","preventionTips":["Only glob fully-written JaCoCo reports.","Re-run coverage generation if a report is truncated.","Validate XML with xmllint before summarizing."],"tags":["python","xml","coverage","scripts","parsing"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}