Skip to content

fix: guard undefined entity on the incoming-message handlers#2922

Open
krobipd wants to merge 1 commit into
ioBroker:masterfrom
krobipd:fix/guard-undefined-entity-handlers
Open

fix: guard undefined entity on the incoming-message handlers#2922
krobipd wants to merge 1 commit into
ioBroker:masterfrom
krobipd:fix/guard-undefined-entity-handlers

Conversation

@krobipd

@krobipd krobipd commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Problem

The adapter occasionally crashes on incoming zigbee traffic (and under compact mode can take the controller with it) — part of the "randomly wobbly" class of failures. Both handlers that run for every incoming message dereference the resolved entity without guarding it, and resolveEntity() can return undefined for a message from a device that does not resolve (a device that is leaving/unknown, or a DB race). Both handlers are async and bound fire-and-forget (herdsman message, controller event/msg), so the throw becomes an unhandled promise rejection.

  • ZigbeeController.handleMessage builds options: entity.options || {} — the line just above already guards entity &&, but this one dereferences entity.options unconditionally → TypeError: Cannot read properties of undefined on an unresolved entity.
  • StatesController.onZigbeeEvent dereferences entity.device at the very top, before its try block.

Fix

  • handleMessage: guard with entity?.options ?? {} and wrap the body in a top-level try/catch (log instead of crashing — it is the central message entry point).
  • onZigbeeEvent: return early when entity/entity.device is missing (an event for an unresolvable entity cannot be processed; everything below needs the device).

No behaviour change for resolved entities. The missing guard is visible directly in the code (the preceding line guards entity, this one does not; event() forwards the entity unconditionally), independent of reproducibility.

Testing

  • node --check passes on both files.
  • Behaviour for normally-resolved messages is unchanged; only the undefined-entity path is now handled instead of throwing.

handleMessage and onZigbeeEvent run for every incoming zigbee message, bound
fire-and-forget on the herdsman 'message' event and the controller 'event'/'msg'
events. resolveEntity() can return undefined for a message from a device that
does not resolve (unknown/leaving device, DB race), and neither path guarded it:

- handleMessage built `options: entity.options || {}` without checking entity
  (the line just above already guards `entity &&`), throwing on undefined entity.
- onZigbeeEvent dereferenced `entity.device` at the top, before its try block.

Since both handlers are async and their callers don't await them, the throw
became an unhandled promise rejection — fatal under compact mode. Guard the
entity (onZigbeeEvent returns early; handleMessage uses `entity?.options ?? {}`)
and wrap handleMessage in a top-level try/catch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@asgothian

asgothian commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

This PR will not go through. Please rework:

  1. changes in statescontroller.js
  • blocking the call should not occur before the debug message is sent
  • the check for !entity || !entity.device makes no sense. Possible options are (!entity) or !(entity?.device) (ResolveEntity either returns a structure with the property device or undefined )
  1. changes in zigbeecontroller.js
  • encapsulating the entire function in a try/catch is the blunt approach, and quite unnecessary. Note that all functions called are either explicitly safeguarding, secured via try/catch, or called via 'emit' (which breaks the try/catch)
  • fix the 'improper' use of || when addressing complex structures (i.e. data.device || data.ieeeAddr => data.device ?? data.ieeeAddr
  • fix the improper use of _modelID (an internal property which should never be addressed directly, as it may no longer be available in the future)
  • Implement guarding against data being undefined (by addressing its properties via data?.

Alternatively, this will return onto the stack of planned reworks and be done when I get to it.

A.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants