Summary
When onboarding an Aqara Camera Hub G350 through the Matter Switch Edge Driver, the camera is recognized correctly and the camera sub-driver loads, but the driver throws repeated runtime errors while handling Descriptor.PartsList.
The crash appears to come from the generic switch_handlers/attribute_handlers.lua parts_list_handler, which assumes device:get_field(fields.ELECTRICAL_SENSOR_EPS) is a table and later evaluates #tree_topology_eps even when that field is nil.
This looks like a driver-side nil-guard bug in the generic Matter Switch Descriptor.PartsList path, not a malformed response from the camera.
Environment
- Driver:
matter-switch
- Protocol: Matter
- Device: Aqara Camera Hub G350
- User-visible name in logs:
Aqara Camera Hub G350
- BasicInformation.SoftwareVersion:
4005020
- Observed endpoint topology from logs:
- EP0: DeviceType
0x0016
- EP1: DeviceType
0x000E
- EP2: DeviceType
0x0142 (Camera)
Expected behavior
Descriptor.PartsList reports for devices that do not participate in electrical sensor / power topology profiling should be ignored safely, or at minimum should not crash if fields.ELECTRICAL_SENSOR_EPS was never initialized.
The device should complete onboarding without repeated thread exceptions.
Actual behavior
The device is added, sub_drivers.camera is lazy-loaded, the profile is updated to camera, and camera capabilities are enabled successfully. However, repeated thread exceptions are thrown while processing Descriptor.PartsList.
Representative runtime error:
[string "switch_handlers/attribute_handlers.lua"]:359: attempt to get length of a nil value (local 'tree_topology_eps')
Reproduction steps
-
Pair/onboard an Aqara Camera Hub G350 to SmartThings over Matter.
-
Watch hub logs during onboarding.
-
Observe:
- the camera sub-driver is loaded,
- the profile is updated to
camera,
- camera attributes are read successfully,
- then repeated exceptions occur in the generic
Descriptor.PartsList handler.
Relevant log excerpts
INFO Matter Switch <MatterDevice ... (Aqara Camera Hub G350)> Lazy loaded driver into dispatcher: sub_drivers.camera
INFO Matter Switch <MatterDevice ... (Aqara Camera Hub G350)> Updating device profile to camera. Enabling the optional capabilities [webrtc, cameraViewportSettings, videoStreamSettings, imageCapture, nightVision] on component 'main', [audioMute, audioVolume] on component 'speaker', and [audioMute, audioVolume] on component 'microphone'
ERROR Matter Switch Aqara Camera Hub G350 thread encountered error:
[string "st/dispatcher.lua"]:270: Error encountered while processing event for <MatterDevice ... (Aqara Camera Hub G350)>:
...
"[string "switch_handlers/attribute_handlers.lua"]:359: attempt to get length of a nil value (local 'tree_topology_eps')"
The same onboarding session also shows successful camera-specific responses, for example:
TwoWayTalkSupport = FULL_DUPLEX
NightVision = AUTO
SpeakerMuted = false
SpeakerVolumeLevel = 80
MicrophoneMuted = false
MicrophoneVolumeLevel = 100
And SmartThings emits the corresponding camera capability events:
webrtc.talkback = true
webrtc.talkbackDuplex = fullDuplex
nightVision = auto
audioMute/audioVolume for speaker and microphone
Analysis
1) The generic main driver is handling Descriptor.PartsList
The main matter-switch driver registers the generic Descriptor.PartsList handler here:
drivers/SmartThings/matter-switch/src/init.lua
clusters.Descriptor.attributes.PartsList.ID -> attribute_handlers.parts_list_handler
2) parts_list_handler is not nil-safe
In drivers/SmartThings/matter-switch/src/switch_handlers/attribute_handlers.lua, the handler does this:
local tree_topology_eps = device:get_field(fields.ELECTRICAL_SENSOR_EPS)
for i, tree_ep_info in pairs(tree_topology_eps or {}) do
...
end
if #tree_topology_eps == 0 then
...
end
If fields.ELECTRICAL_SENSOR_EPS was never initialized, this becomes:
- iteration over
pairs(tree_topology_eps or {}) -> safe
#tree_topology_eps -> crashes on nil
That exactly matches the observed runtime error.
|
function AttributeHandlers.parts_list_handler(driver, device, ib, response) |
|
if device:get_field(fields.profiling_data.POWER_TOPOLOGY) ~= nil then |
|
device.log.warn("Received a PartsList response after power topology has already been determined. Ignoring this response.") |
|
return |
|
end |
|
local tree_topology_eps = device:get_field(fields.ELECTRICAL_SENSOR_EPS) |
|
for i, tree_ep_info in pairs(tree_topology_eps or {}) do |
|
if ib.endpoint_id == tree_ep_info.endpoint_id then |
|
-- since EP response is being handled here, remove it from the ELECTRICAL_SENSOR_EPS table |
|
switch_utils.remove_field_index(device, fields.ELECTRICAL_SENSOR_EPS, i) |
|
local associated_endpoints_ids = {} |
|
for _, element in pairs(ib.data.elements or {}) do |
|
table.insert(associated_endpoints_ids, element.value) |
|
end |
|
-- set the required profile elements ("-power", etc.) to one of these EP IDs for later profiling. |
|
-- set an assigned child key in the case this will emit events on an EDGE_CHILD device |
|
switch_utils.set_fields_for_electrical_sensor_endpoint(device, tree_ep_info, associated_endpoints_ids) |
|
break |
|
end |
|
end |
|
if #tree_topology_eps == 0 then -- in other words, all PartsList attribute responses for TREE Electrical Sensor EPs have been handled |
|
device:set_field(fields.profiling_data.POWER_TOPOLOGY, clusters.PowerTopology.types.Feature.TREE_TOPOLOGY, {persist=true}) |
|
device_cfg.match_profile(driver, device) |
|
end |
|
end |
3) There appears to be a second similar nil hazard
available_endpoints_handler appears to have the same pattern:
local set_topology_eps = device:get_field(fields.ELECTRICAL_SENSOR_EPS)
for i, set_ep_info in pairs(set_topology_eps or {}) do
...
end
if #set_topology_eps == 0 then
...
end
So the same nil-guard fix may be needed there as well.
4) This does not look like an Aqara camera payload problem
The device successfully returns:
Descriptor.DeviceTypeList
Descriptor.PartsList
CameraAvStreamManagement.AttributeList
TwoWayTalkSupport
NightVision
Speaker* / Microphone* attributes
The camera sub-driver also updates the profile and emits expected camera capability events.
So the issue appears to be:
- normal Matter responses from the device
- generic main-driver descriptor handling crashes on missing electrical topology state
5) Why this may affect more than this one device
This may affect any Matter device that:
- triggers the generic
Descriptor.PartsList path in the main driver,
- but never initializes
fields.ELECTRICAL_SENSOR_EPS.
A Matter camera is one clear example because it loads the camera sub-driver but still seems to receive the generic main-driver Descriptor.PartsList handling.
Suggested fix
At minimum, both handlers should early-return unless fields.ELECTRICAL_SENSOR_EPS is a table.
For example:
local tree_topology_eps = device:get_field(fields.ELECTRICAL_SENSOR_EPS)
if type(tree_topology_eps) ~= "table" then
return
end
and similarly:
local set_topology_eps = device:get_field(fields.ELECTRICAL_SENSOR_EPS)
if type(set_topology_eps) ~= "table" then
return
end
Alternatively:
@@ -316,7 +316,7 @@
--- In the case there are multiple endpoints supporting the PowerTopology cluster with
--- SET feature, all AvailableEndpoints responses must be handled before profiling.
function AttributeHandlers.available_endpoints_handler(driver, device, ib, response)
- local set_topology_eps = device:get_field(fields.ELECTRICAL_SENSOR_EPS)
+ local set_topology_eps = device:get_field(fields.ELECTRICAL_SENSOR_EPS) or {}
for i, set_ep_info in pairs(set_topology_eps or {}) do
if ib.endpoint_id == set_ep_info.endpoint_id then
-- since EP response is being handled here, remove it from the ELECTRICAL_SENSOR_EPS table
@@ -341,7 +341,7 @@
-- [[ DESCRIPTOR CLUSTER ATTRIBUTES ]] --
function AttributeHandlers.parts_list_handler(driver, device, ib, response)
- local tree_topology_eps = device:get_field(fields.ELECTRICAL_SENSOR_EPS)
+ local tree_topology_eps = device:get_field(fields.ELECTRICAL_SENSOR_EPS) or {}
for i, tree_ep_info in pairs(tree_topology_eps or {}) do
if ib.endpoint_id == tree_ep_info.endpoint_id then
-- since EP response is being handled here, remove it from the ELECTRICAL_SENSOR_EPS table
That would avoid:
- crashing on
#nil
- incorrectly treating non-electrical devices as candidates for power topology profiling
A more structural alternative would be to avoid routing Descriptor.PartsList / PowerTopology.AvailableEndpoints through these generic profiling handlers unless the device was already identified as having relevant electrical sensor / power topology endpoints.
Additional observations
Despite the exceptions, onboarding continues far enough that:
- the camera profile is applied,
- the
camera sub-driver is active,
- camera capabilities are populated.
So the bug seems non-fatal but noisy, and may still interfere with complete initialization or make onboarding flaky.
Raw log payload available
I can provide the full onboarding log if needed, but the key lines are included above.
Summary
When onboarding an Aqara Camera Hub G350 through the Matter Switch Edge Driver, the camera is recognized correctly and the
camerasub-driver loads, but the driver throws repeated runtime errors while handlingDescriptor.PartsList.The crash appears to come from the generic
switch_handlers/attribute_handlers.luaparts_list_handler, which assumesdevice:get_field(fields.ELECTRICAL_SENSOR_EPS)is a table and later evaluates#tree_topology_epseven when that field isnil.This looks like a driver-side nil-guard bug in the generic Matter Switch
Descriptor.PartsListpath, not a malformed response from the camera.Environment
matter-switchAqara Camera Hub G35040050200x00160x000E0x0142(Camera)Expected behavior
Descriptor.PartsListreports for devices that do not participate in electrical sensor / power topology profiling should be ignored safely, or at minimum should not crash iffields.ELECTRICAL_SENSOR_EPSwas never initialized.The device should complete onboarding without repeated thread exceptions.
Actual behavior
The device is added,
sub_drivers.camerais lazy-loaded, the profile is updated tocamera, and camera capabilities are enabled successfully. However, repeated thread exceptions are thrown while processingDescriptor.PartsList.Representative runtime error:
Reproduction steps
Pair/onboard an Aqara Camera Hub G350 to SmartThings over Matter.
Watch hub logs during onboarding.
Observe:
camera,Descriptor.PartsListhandler.Relevant log excerpts
The same onboarding session also shows successful camera-specific responses, for example:
And SmartThings emits the corresponding camera capability events:
Analysis
1) The generic main driver is handling
Descriptor.PartsListThe main
matter-switchdriver registers the genericDescriptor.PartsListhandler here:drivers/SmartThings/matter-switch/src/init.luaclusters.Descriptor.attributes.PartsList.ID -> attribute_handlers.parts_list_handler2)
parts_list_handleris not nil-safeIn
drivers/SmartThings/matter-switch/src/switch_handlers/attribute_handlers.lua, the handler does this:If
fields.ELECTRICAL_SENSOR_EPSwas never initialized, this becomes:pairs(tree_topology_eps or {})-> safe#tree_topology_eps-> crashes on nilThat exactly matches the observed runtime error.
SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/switch_handlers/attribute_handlers.lua
Lines 347 to 371 in 09cb31c
3) There appears to be a second similar nil hazard
available_endpoints_handlerappears to have the same pattern:So the same nil-guard fix may be needed there as well.
4) This does not look like an Aqara camera payload problem
The device successfully returns:
Descriptor.DeviceTypeListDescriptor.PartsListCameraAvStreamManagement.AttributeListTwoWayTalkSupportNightVisionSpeaker*/Microphone*attributesThe camera sub-driver also updates the profile and emits expected camera capability events.
So the issue appears to be:
5) Why this may affect more than this one device
This may affect any Matter device that:
Descriptor.PartsListpath in the main driver,fields.ELECTRICAL_SENSOR_EPS.A Matter camera is one clear example because it loads the camera sub-driver but still seems to receive the generic main-driver
Descriptor.PartsListhandling.Suggested fix
At minimum, both handlers should early-return unless
fields.ELECTRICAL_SENSOR_EPSis a table.For example:
and similarly:
Alternatively:
That would avoid:
#nilA more structural alternative would be to avoid routing
Descriptor.PartsList/PowerTopology.AvailableEndpointsthrough these generic profiling handlers unless the device was already identified as having relevant electrical sensor / power topology endpoints.Additional observations
Despite the exceptions, onboarding continues far enough that:
camerasub-driver is active,So the bug seems non-fatal but noisy, and may still interfere with complete initialization or make onboarding flaky.
Raw log payload available
I can provide the full onboarding log if needed, but the key lines are included above.