`xpath:` filter fails with a blank "Exception:" on some pages — works fine with `xpath1:`
triage
**Describe the bug**
One of my watches started showing just `Exception:` with no message after it, on every check.
The logs show the crash happens inside the elementpath library while it's reading the page, before my filter even runs. It looks like something about this particular page's HTML trips it up.
Changing the filter to `xpath1://div[@id="main-content"]` fixes it, so this isn't blocking me — filing since the blank error made it hard to figure out what was going on, and I'm guessing other people will hit the same page-dependent crash and have nothing to go on.
Two possible improvements here: fixing (or working around) the crash itself, and surfacing *something* in the UI when an exception has no message, since `Exception:` with nothing after it is a dead end without log access.
**Version**
0.55.8
**How did you install?**
Docker
**To Reproduce**
Steps to reproduce the behavior:
1. Create a watch for https://eero.com/support/articles/209636523-eero-Software-Release-Notes
2. Set the include filter to `xpath://div[@id="main-content"]`
3. Recheck the watch
4. Watch shows `Exception:` with no message
**Expected behavior**
The filter selects the div (as it does with `xpath1:`), or at minimum the error shown in the UI says what went wrong.
**Log output**
Trimmed:
```
File "/usr/local/elementpath/tree_builders.py", line 309, in build_lxml_node_tree
children, parent = iterators.pop(), ancestors.pop()
IndexError: pop from an empty deque
During handling of the above exception, another exception occurred:
...
File "/usr/local/elementpath/tree_builders.py", line 316, in build_lxml_node_tree
assert callable(elem.tag)
AssertionError
```
<details>
<summary>Full traceback</summary>
```
2026-08-21 07:59:40.565 | ERROR | changedetectionio.worker:async_update_worker:405 - Worker 5 exception processing watch UUID: ea1a0610-d52c-44f4-8e8b-2f2f96aef01e
2026-08-21 07:59:40.565 | ERROR | changedetectionio.worker:async_update_worker:406 - Worker 5 full exception details:
Traceback (most recent call last):
File "/usr/local/elementpath/tree_builders.py", line 309, in build_lxml_node_tree
children, parent = iterators.pop(), ancestors.pop()
IndexError: pop from an empty deque
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.11/threading.py", line 1002, in _bootstrap
self._bootstrap_inner()
File "/usr/local/lib/python3.11/threading.py", line 1045, in _bootstrap_inner
self.run()
File "/usr/local/lib/python3.11/threading.py", line 982, in run
self._target(*self._args, **self._kwargs)
File "/app/changedetectionio/worker_pool.py", line 58, in run
self.loop.run_until_complete(
File "/usr/local/lib/python3.11/asyncio/base_events.py", line 641, in run_until_complete
self.run_forever()
File "/usr/local/lib/python3.11/asyncio/base_events.py", line 608, in run_forever
self._run_once()
File "/usr/local/lib/python3.11/asyncio/base_events.py", line 1936, in _run_once
handle._run()
File "/usr/local/lib/python3.11/asyncio/events.py", line 84, in _run
self._context.run(self._callback, *self._args)
File "/app/changedetectionio/worker_pool.py", line 139, in start_single_async_worker
result = await async_update_worker(worker_id, update_q, notification_q, app, datastore, executor)
> File "/app/changedetectionio/worker.py", line 194, in async_update_worker
changed_detected, update_obj, contents = await loop.run_in_executor(
File "/usr/local/lib/python3.11/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
File "/app/changedetectionio/worker.py", line 196, in <lambda>
lambda: update_handler.run_changedetection(watch=watch)
File "/app/changedetectionio/processors/text_json_diff/processor.py", line 515, in run_changedetection
html_content = content_processor.apply_include_filters(html_content, stream_content_type)
File "/app/changedetectionio/processors/text_json_diff/processor.py", line 349, in apply_include_filters
filtered_content += html_tools.xpath_filter(
File "/app/changedetectionio/html_tools.py", line 304, in xpath_filter
r = elementpath.select(tree, xpath_filter.strip(), namespaces=namespaces, parser=SafeXPath3Parser)
File "/usr/local/elementpath/xpath_selectors.py", line 75, in select
context = XPathContext(root, namespaces, uri, fragment, item, position, size,
File "/usr/local/elementpath/xpath_context.py", line 124, in __init__
self.root = get_node_tree(root, self.namespaces, uri, fragment)
File "/usr/local/elementpath/tree_builders.py", line 69, in get_node_tree
return build_lxml_node_tree(
File "/usr/local/elementpath/tree_builders.py", line 316, in build_lxml_node_tree
assert callable(elem.tag)
AssertionError
```
</details>
0 条评论