Summary
A Kasa camera/doorbell that answers legacy discovery on UDP/9999 causes
get_device_class_from_sys_info to raise a bare KeyError, which escapes
Discover.datagram_received entirely and surfaces as an unhandled asyncio callback
exception in the consuming application.
This is the library-side cause of home-assistant/core#138866 (open since 2025-02-19,
labelled waiting-for-upstream).
This is not a request for camera support — #467 already tracks that. This is only a
request that an unsupported device type fail the way the library's own callers already
expect it to fail.
Reproduction
python-kasa 0.10.2, Python 3.14.
Any device reporting "type": "IOT.IPCAMERA" in its legacy get_sysinfo response. Here
it is a Kasa KD110(US) video doorbell, hw 4.0, fw 2.3.26 Build 20240508. Three of
them on the network produce three tracebacks per discovery run, indefinitely.
File "kasa/discover.py", line 377, in datagram_received
device = device_func(info, config)
File "kasa/discover.py", line 742, in _get_device_instance_legacy
device_class = cast(type[IotDevice], Discover._get_device_class(info))
File "kasa/discover.py", line 722, in _get_device_class
return get_device_class_from_sys_info(info)
File "kasa/device_factory.py", line 145, in get_device_class_from_sys_info
return TYPE_TO_CLASS[IotDevice._get_device_type_from_sys_info(sysinfo)]
KeyError: <DeviceType.Camera: 'camera'>
Cause
kasa/device_factory.py:135-145 — DeviceType.Camera was commented out of
TYPE_TO_CLASS in #1480 ("Disable iot camera creation until more complete", merged
2025-01-25), but the lookup remained a bare subscript:
TYPE_TO_CLASS = {
...
# Disabled until properly implemented
# DeviceType.Camera: IotCamera,
}
return TYPE_TO_CLASS[IotDevice._get_device_type_from_sys_info(sysinfo)]
_get_device_type_from_sys_info still maps IOT.IPCAMERA to DeviceType.Camera, so the
subscript raises KeyError.
datagram_received guards only UnsupportedDeviceError (discover.py:378) and
KasaException (:385). KeyError is neither, so it propagates out of the protocol
callback. Because the raise is at :377, the code at :391-394 that records the device
and invokes on_discovered never runs — so downstream consumers cannot even see, filter
or ignore the device.
The fix already exists
#1571 ("Raise UnsupportedDeviceError for unsupported legacy device types", @rytilahti,
2025-08-31) does exactly this, and adds the fixture
incomplete_iotcamera = _make_unsupported("IOT.IPCAMERA", "XOR").
It was stale-labelled 2025-11-30 and auto-closed 2025-12-08 with no human review.
kasa/device_factory.py is byte-identical between 0.10.2 and master today.
Its author flagged one concern in the description — "The test might not be correct, as
this was also raising even before adding the new raise, needs to be verified." — which
looks like the only thing standing between it and merge.
Impact
Downstream (Home Assistant) this produces a 19-line traceback per responding camera per
15-minute discovery cycle, indefinitely, for devices the user has deliberately chosen not
to integrate. On my instance that was ~288 tracebacks/day and about 94% of the retained
log file — it evicts unrelated evidence, which is how I found it.
Summary
A Kasa camera/doorbell that answers legacy discovery on UDP/9999 causes
get_device_class_from_sys_infoto raise a bareKeyError, which escapesDiscover.datagram_receivedentirely and surfaces as an unhandled asyncio callbackexception in the consuming application.
This is the library-side cause of home-assistant/core#138866 (open since 2025-02-19,
labelled
waiting-for-upstream).This is not a request for camera support — #467 already tracks that. This is only a
request that an unsupported device type fail the way the library's own callers already
expect it to fail.
Reproduction
python-kasa 0.10.2, Python 3.14.
Any device reporting
"type": "IOT.IPCAMERA"in its legacyget_sysinforesponse. Hereit is a Kasa KD110(US) video doorbell, hw 4.0, fw
2.3.26 Build 20240508. Three ofthem on the network produce three tracebacks per discovery run, indefinitely.
Cause
kasa/device_factory.py:135-145—DeviceType.Camerawas commented out ofTYPE_TO_CLASSin #1480 ("Disable iot camera creation until more complete", merged2025-01-25), but the lookup remained a bare subscript:
_get_device_type_from_sys_infostill mapsIOT.IPCAMERAtoDeviceType.Camera, so thesubscript raises
KeyError.datagram_receivedguards onlyUnsupportedDeviceError(discover.py:378) andKasaException(:385).KeyErroris neither, so it propagates out of the protocolcallback. Because the raise is at
:377, the code at:391-394that records the deviceand invokes
on_discoverednever runs — so downstream consumers cannot even see, filteror ignore the device.
The fix already exists
#1571 ("Raise UnsupportedDeviceError for unsupported legacy device types", @rytilahti,
2025-08-31) does exactly this, and adds the fixture
incomplete_iotcamera = _make_unsupported("IOT.IPCAMERA", "XOR").It was stale-labelled 2025-11-30 and auto-closed 2025-12-08 with no human review.
kasa/device_factory.pyis byte-identical between0.10.2andmastertoday.Its author flagged one concern in the description — "The test might not be correct, as
this was also raising even before adding the new raise, needs to be verified." — which
looks like the only thing standing between it and merge.
Impact
Downstream (Home Assistant) this produces a 19-line traceback per responding camera per
15-minute discovery cycle, indefinitely, for devices the user has deliberately chosen not
to integrate. On my instance that was ~288 tracebacks/day and about 94% of the retained
log file — it evicts unrelated evidence, which is how I found it.