Describe the bug
While a device is offline, apyhiveapi.heating and apyhiveapi.hotwater log an ERROR on every poll, and the message is just the bare key name — 'mode'. No device name, no context, no traceback.
I collected 3,005 of each (6,010 lines) in a single 13-hour outage, at one pair every 15 seconds:
2026-08-19 00:51:55.208 ERROR (MainThread) [apyhiveapi.heating] 'mode'
2026-08-19 00:51:55.209 ERROR (MainThread) [apyhiveapi.hotwater] 'mode'
2026-08-19 00:52:10.210 ERROR (MainThread) [apyhiveapi.heating] 'mode'
...
The cause is heating.py:
try:
data = self.session.data.products[device["hiveID"]]
state = data["state"]["mode"]
if state == "BOOST":
state = data["props"]["previous"]["mode"]
final = HIVETOHA[self.heatingType].get(state, state)
except KeyError as e:
_LOGGER.error(e) # <- logs only the missing key name
_LOGGER.error(e) on a KeyError renders as the repr of the key, so the operator sees 'mode' and nothing else. hotwater.py has the same shape, and device_attributes.py has a third instance.
Two smaller points worth noting:
- The
try covers both data["state"]["mode"] and data["props"]["previous"]["mode"], so the log line cannot tell you which one was missing.
helper/hive_helper.py errorCheck() already has a dedupe mechanism (session.config.errorList) so that "Device offline could not update entity" is logged once per device rather than every poll. The getMode/getState handlers don't use it, so a known-offline device still generates ERROR-level noise indefinitely.
To Reproduce
- Have a device go offline such that its product node no longer carries
state.mode. (Mine came back from the API with error: MALFORMED_NODE_DESCRIPTOR, so the product was skipped and the cached entry had no state.)
- Leave HA running.
- Watch
apyhiveapi.heating / apyhiveapi.hotwater emit an ERROR every 15 s indefinitely.
Expected behaviour
A known-offline or malformed device should log once, at WARNING, with enough context to act on — something like:
except KeyError as e:
_LOGGER.warning(
"Heating %s: product data missing key %s (device offline or malformed node)",
device.get("haName", device.get("hiveID")), e,
)
and ideally routed through the same errorList dedupe that errorCheck() already uses, so it doesn't repeat every poll.
Additional context
This matters beyond tidiness: at ERROR level and 5,760 lines/day it dominates the log, pushes genuinely useful entries out of the retained window, and trains people to ignore red text. It's also actively misleading — a bare 'mode' gives no indication that the underlying condition is simply "this device is offline", which the library already knows and already reports properly elsewhere.
Versions
- Home Assistant Core 2026.8.2 (HAOS)
- Hive-Custom-Component 2026.8.0
- pyhive-integration 1.0.9
Describe the bug
While a device is offline,
apyhiveapi.heatingandapyhiveapi.hotwaterlog an ERROR on every poll, and the message is just the bare key name —'mode'. No device name, no context, no traceback.I collected 3,005 of each (6,010 lines) in a single 13-hour outage, at one pair every 15 seconds:
The cause is
heating.py:_LOGGER.error(e)on aKeyErrorrenders as the repr of the key, so the operator sees'mode'and nothing else.hotwater.pyhas the same shape, anddevice_attributes.pyhas a third instance.Two smaller points worth noting:
trycovers bothdata["state"]["mode"]anddata["props"]["previous"]["mode"], so the log line cannot tell you which one was missing.helper/hive_helper.py errorCheck()already has a dedupe mechanism (session.config.errorList) so that "Device offline could not update entity" is logged once per device rather than every poll. ThegetMode/getStatehandlers don't use it, so a known-offline device still generates ERROR-level noise indefinitely.To Reproduce
state.mode. (Mine came back from the API witherror: MALFORMED_NODE_DESCRIPTOR, so the product was skipped and the cached entry had nostate.)apyhiveapi.heating/apyhiveapi.hotwateremit an ERROR every 15 s indefinitely.Expected behaviour
A known-offline or malformed device should log once, at WARNING, with enough context to act on — something like:
and ideally routed through the same
errorListdedupe thaterrorCheck()already uses, so it doesn't repeat every poll.Additional context
This matters beyond tidiness: at ERROR level and 5,760 lines/day it dominates the log, pushes genuinely useful entries out of the retained window, and trains people to ignore red text. It's also actively misleading — a bare
'mode'gives no indication that the underlying condition is simply "this device is offline", which the library already knows and already reports properly elsewhere.Versions