-
Notifications
You must be signed in to change notification settings - Fork 21
Description
Hi @lawtancool,
First off, thanks for creating this library! I'm using it via your hass-control4 integration. It looks like the library doesn't handle corrupted XML from the director, which makes it tough to debug.
My Situation
My Home Assistant instance was failing to set up the integration, and I kept getting this traceback. After a lot of digging, it turns out my Control4 Director was sending back malformed XML.
2025-07-25 20:16:19.280 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry control4_hc800_000FFF580817 for control4
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/config_entries.py", line 749, in __async_setup_with_context
result = await component.async_setup_entry(hass, self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/config/custom_components/control4/__init__.py", line 123, in async_setup_entry
await entry_data[CONF_DIRECTOR].getUiConfiguration()
File "/usr/local/lib/python3.13/site-packages/pyControl4/director.py", line 303, in getUiConfiguration
return await self.sendGetRequest("/api/v1/agents/ui_configuration")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.13/site-packages/pyControl4/director.py", line 64, in sendGetRequest
await checkResponseForError(await resp.text())
File "/usr/local/lib/python3.13/site-packages/pyControl4/error_handling.py", line 98, in checkResponseForError
dictionary = xmltodict.parse(response_text)
File "/usr/local/lib/python3.13/site-packages/xmltodict.py", line 359, in parse
parser.Parse(xml_input, True)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
xml.parsers.expat.ExpatError: mismatched tag: line 6, column 2
The Problem
In pyControl4/error_handling.py, the checkResponseForError function uses a broad try...except that catches the ExpatError but then just ignores it. This makes the library think everything is fine, when really the controller sent broken data.
A Possible Fix?
Maybe the error handling could be a bit more specific? Instead of catching every exception, it could specifically look for the ExpatError and raise a custom error. That would make it much clearer that the problem is coming from the controller's side.
Something like this might work:
# In pyControl4/error_handling.py
from xml.parsers.expat import ExpatError
# ...
def checkResponseForError(response_text):
try:
dictionary = xmltodict.parse(response_text)
except ExpatError as e:
# This would make it super clear that the controller sent bad XML
raise C4CorruptXMLResponse(f"Controller sent malformed XML: {e}") from e
except Exception:
# Keep this for other non-XML cases
return
This would have saved me a ton of time troubleshooting!
Thanks for looking into this!