Skip to content

fix(matter): tolerate MatterError on set_lock_user UPDATE; map on CREATE - #1245

Merged
raman325 merged 1 commit into
mainfrom
fix/matter-tolerate-set-lock-user-sdk-errors
Jun 11, 2026
Merged

fix(matter): tolerate MatterError on set_lock_user UPDATE; map on CREATE#1245
raman325 merged 1 commit into
mainfrom
fix/matter-tolerate-set-lock-user-sdk-errors

Conversation

@raman325

Copy link
Copy Markdown
Owner

Proposed change

Production regression observed on a real Matter lock (`lock.raman_office`, slot 1): `set_lock_user` on an existing user occasionally throws `matter_server.common.errors.UnknownError: InteractionModelError: InvalidCommand (0x85)`. `UnknownError` is a `MatterError` subclass, not a `HomeAssistantError` subclass, so the original `except HomeAssistantError` at `matter.py:379` silently let it bubble past. The seam's catchall in `_async_tick_impl` then routed every failure to `suspend_slot`, creating a spurious `slot_suspended*` repair issue even though the lock user record was fine and the credential write would have succeeded.

The docstring at the catch site already documented the right intent:

`set_lock_user` here is a metadata-only name update. The historical contract (PR #1077) tolerated name-set failures so a transient 500 or a name the lock rejects does not block the subsequent credential write.

The fix widens the catch to `(HomeAssistantError, MatterError)` so the contract holds for Matter-SDK-side rejections too.

For the CREATE path we cannot tolerate the failure — without an allocated `user_index` the subsequent credential write has no target. The fix adds a `MatterError → LockOperationFailed` mapping so the seam retries through the normal backoff path rather than the catchall suspend (which would still spuriously create a repair issue without giving the lock a chance to recover).

Production traceback

```
ERROR [custom_components.lcm.domain.sync] Raman's Office: lock.raman_office slot 1:
Unexpected error during set usercode. Sync suspended for this lock to prevent
infinite retry loop. Error: UnknownError: InteractionModelError: InvalidCommand (0x85)

File "/config/custom_components/lcm/providers/matter.py", line 373, in async_set_user
await set_lock_user(client, node, user_index=existing_user_index, user_name=user.name)
File "matter_server/client/client.py", line 611, in send_command
return await future
matter_server.common.errors.UnknownError: InteractionModelError: InvalidCommand (0x85)
```

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New feature (which adds functionality)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Test plan

  • Full suite passes locally (1157/1157)
  • New `test_set_user_update_tolerates_matter_sdk_error` pins that `UnknownError("InvalidCommand (0x85)")` on UPDATE is logged and the `user_index` is still returned for the credential write
  • New `test_set_user_create_raises_operation_failed_on_matter_sdk_error` pins that `UnknownError` on CREATE surfaces as `LockOperationFailed` instead of bubbling raw
  • Live Matter lock: confirm the slot_suspended repair issue stops re-firing after deploy

🤖 Generated with Claude Code

Production regression observed on a real Matter lock: set_lock_user
on an existing user occasionally throws matter_server.common.errors.
UnknownError: InteractionModelError: InvalidCommand (0x85).
UnknownError is a MatterError subclass, NOT a HomeAssistantError
subclass, so the original except HomeAssistantError at matter.py:379
silently let it bubble past. The seam's catchall in _async_tick_impl
then routed every failure to _suspend_slot, creating a spurious
slot_suspended_* repair issue even though the underlying lock user
record was fine and the credential write would have succeeded.

The docstring at the catch site already documented the right intent:
the rename is metadata-only and the historical contract (PR #1077)
tolerates name-set failures. The fix widens the catch to
(HomeAssistantError, MatterError) so the contract holds for
Matter-SDK-side rejections too.

For the CREATE path we cannot tolerate the failure -- without an
allocated user_index the subsequent credential write has no target.
The fix adds a MatterError -> LockOperationFailed mapping so the
seam retries through the normal backoff path rather than the
catchall suspend.

Regression tests pin both branches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 9c5984fffec0
Copilot AI review requested due to automatic review settings June 11, 2026 03:50
@github-actions github-actions Bot added the python Pull requests that update Python code label Jun 11, 2026
@github-actions github-actions Bot added the bug Something isn't working label Jun 11, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a regression in the Matter provider where Matter-SDK exceptions from set_lock_user were not being handled per the established contract, causing the sync seam to treat transient/benign failures as “unexpected” and incorrectly suspend slots (creating repair issues).

Changes:

  • Expand the UPDATE (rename-only) exception handling to also tolerate MatterError so credential writes can still proceed when name updates are rejected by the lock/Matter SDK.
  • Map MatterError on the CREATE path to LockOperationFailed so the seam retries via normal backoff instead of falling into the catchall suspend path.
  • Add targeted tests covering UPDATE tolerance and CREATE error mapping for Matter-SDK errors (UnknownError).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
custom_components/lock_code_manager/providers/matter.py Broadens exception handling for set_lock_user to preserve the UPDATE tolerance contract and route CREATE failures through retry semantics.
tests/providers/matter/test_provider.py Adds regression tests ensuring Matter-SDK errors are handled correctly on UPDATE vs CREATE.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.98%. Comparing base (38295e4) to head (9267528).
✅ All tests successful. No failed tests found.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #1245   +/-   ##
=======================================
  Coverage   96.98%   96.98%           
=======================================
  Files          53       53           
  Lines        6168     6171    +3     
  Branches      461      461           
=======================================
+ Hits         5982     5985    +3     
  Misses        186      186           
Flag Coverage Δ
python 97.52% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...m_components/lock_code_manager/providers/matter.py 99.35% <100.00%> (+<0.01%) ⬆️
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@raman325
raman325 merged commit 1c5cdad into main Jun 11, 2026
19 checks passed
@raman325
raman325 deleted the fix/matter-tolerate-set-lock-user-sdk-errors branch June 11, 2026 03:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working python Pull requests that update Python code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants