read_file(filetype="docx") fails with XMLSyntaxError on valid Word documents with complex relationships

Author: gnai-creatorCreated Feb 26, 2026Updated Feb 26, 2026

Description

The read_docx() function in livebench/tools/productivity/file_reading.py crashes when
reading DOCX files that contain malformed or complex XML in their internal _rels
(relationships) metadata. This causes a complete inability to read reference files,
making the agent unable to complete the task regardless of LLM capability.

Steps to Reproduce

  1. Run a LiveBench session with a task that provides a DOCX reference file (~2.8MB,
    complex document with embedded objects/hyperlinks)
  2. Agent calls read_file(filetype="docx", file_path="...Research Material.docx")
  3. Function crashes immediately

Error Output

lxml.etree.XMLSyntaxError: attributes construct error, line 2, column 258 (,
line 2)

Full traceback: File "livebench/tools/productivity/file_reading.py", line 187, in read_docx doc = Document(str(docx_path)) File ".../docx/api.py", line 27, in Document document_part = cast("DocumentPart", Package.open(docx).main_document_part) File ".../docx/opc/pkgreader.py", line 62, in _srels_for return _SerializedRelationships.load_from_xml(source_uri.baseURI, rels_xml) File ".../docx/opc/pkgreader.py", line 251, in load_from_xml rels_elm = parse_xml(rels_item_xml) File ".../docx/opc/oxml.py", line 38, in parse_xml return etree.fromstring(text, oxml_parser) lxml.etree.XMLSyntaxError: attributes construct error, line 2, column 258

Root Cause

python-docx uses lxml with strict XML parsing to read the .rels files inside the DOCX
ZIP archive. Some Word documents (especially those created by newer versions of Microsoft Word, or with complex embedded objects/hyperlinks) produce relationship XML
that lxml's strict parser rejects.

The current code at line 186-210 has no fallback:

def read_docx(docx_path: Path) -> str: try: doc = Document(str(docx_path)) # <-- crashes here, no recovery # ... except Exception as e: raise RuntimeError(f"Failed to read DOCX file: {str(e)}") # <-- just re-raises

Impact

  • Severity: High — Agent cannot read reference files, making the entire task impossible
  • Observed in: LiveBench session 2025-02-13, task 46b34f78-6c06-4416-87e2-77b6d8b20ce9
    (Finance, $448.08 max payment)
  • Agent retried twice with the same error, wasting 2 of 15 iterations
  • Affects any agent (not LLM-specific)

Suggested Fix

Add fallback methods when python-docx fails. For example:

def read_docx(docx_path: Path) -> str: # Method 1: python-docx (default) try: from docx import Document doc = Document(str(docx_path)) paragraphs = [p.text for p in doc.paragraphs if p.text.strip()] tables_text = [] for table in doc.tables: table_data = [] for row in table.rows: row_data = [cell.text.strip() for cell in row.cells] table_data.append(" | ".join(row_data)) if table_data: tables_text.append("\n".join(table_data)) all_text = "\n\n".join(paragraphs) if tables_text: all_text += "\n\n=== TABLES ===\n\n" + "\n\n".join(tables_text) return all_text except Exception: pass

  # Method 2: zipfile + lxml recover mode (handles malformed XML)
  try:
      import zipfile
      from lxml import etree
      with zipfile.ZipFile(str(docx_path), 'r') as z:
          xml_content = z.read('word/document.xml')
          parser = etree.XMLParser(recover=True)
          tree = etree.fromstring(xml_content, parser)
          ns = {'w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'}  
          texts = [node.text for node in tree.iter(f'{{{ns["w"]}}}t') if node.text]   
          return '\n'.join(texts)
  except Exception:
      pass

  # Method 3: mammoth (HTML-based extraction)
  try:
      import mammoth
      with open(str(docx_path), 'rb') as f:
          result = mammoth.extract_raw_text(f)
          return result.value
  except ImportError:
      pass

  raise RuntimeError(f"All DOCX reading methods failed for: {docx_path}")

Environment

  • OS: Windows 11
  • Python: 3.12
  • python-docx: latest
  • lxml: latest
  • File: Research Material.docx (2,799,328 bytes)