Summary
device_reader.py:280 calls self.notify_future.set_result(self.notify_response) on a future that may already be in the done state, raising asyncio.exceptions.InvalidStateError: invalid state.
The traceback floods Home Assistant logs (we're seeing 50+ occurrences over a single ~16 minute window) and shows up as Task exception was never retrieved because the resulting exception is never awaited.
Traceback
ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved (task: None)
Traceback (most recent call last):
File "/usr/local/lib/python3.14/site-packages/bluetti_bt_lib/bluetooth/device_reader.py", line 280, in _notification_handler
self.notify_future.set_result(self.notify_response)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
asyncio.exceptions.InvalidStateError: invalid state
Environment
bluetti-bt-lib: 0.1.6
- Consumer:
Patrick762/hassio-bluetti-bt v0.2.1 (Home Assistant custom integration, pins this lib at 0.1.6 in manifest.json)
- Home Assistant: 2026.4.3 on HA OS 17.2 / Python 3.14
- Device: Bluetti AC300
Likely cause
_notification_handler is invoked by bleak whenever a BLE notification arrives on the characteristic. If a second notification arrives before the awaiting consumer has cleared self.notify_future, the second call to set_result hits an already-completed future.
The same race likely fires when:
- the BLE peer sends spurious / duplicated notifications
- the read coroutine is cancelled after
set_result is queued but before the future is consumed and reset
Suggested fix
Guard the set_result against the already-done state, e.g.:
def _notification_handler(self, ...):
...
if self.notify_future is not None and not self.notify_future.done():
self.notify_future.set_result(self.notify_response)
This keeps the first response and silently drops late-arriving duplicates — the consumer-side timeout already handles missed responses, so dropping is safe.
Acceptance
- No
InvalidStateError / Task exception was never retrieved traces in HA logs from device_reader.py.
Summary
device_reader.py:280callsself.notify_future.set_result(self.notify_response)on a future that may already be in the done state, raisingasyncio.exceptions.InvalidStateError: invalid state.The traceback floods Home Assistant logs (we're seeing 50+ occurrences over a single ~16 minute window) and shows up as
Task exception was never retrievedbecause the resulting exception is never awaited.Traceback
Environment
bluetti-bt-lib: 0.1.6Patrick762/hassio-bluetti-btv0.2.1 (Home Assistant custom integration, pins this lib at 0.1.6 inmanifest.json)Likely cause
_notification_handleris invoked bybleakwhenever a BLE notification arrives on the characteristic. If a second notification arrives before the awaiting consumer has clearedself.notify_future, the second call toset_resulthits an already-completed future.The same race likely fires when:
set_resultis queued but before the future is consumed and resetSuggested fix
Guard the
set_resultagainst the already-done state, e.g.:This keeps the first response and silently drops late-arriving duplicates — the consumer-side timeout already handles missed responses, so dropping is safe.
Acceptance
InvalidStateError/Task exception was never retrievedtraces in HA logs fromdevice_reader.py.