Skip to content

fix: prevent KeyError when setting up lock after previous deletion#595

Open
raman325 wants to merge 11 commits intoFutureTense:mainfrom
raman325:fix/593-keyerror-setup
Open

fix: prevent KeyError when setting up lock after previous deletion#595
raman325 wants to merge 11 commits intoFutureTense:mainfrom
raman325:fix/593-keyerror-setup

Conversation

@raman325
Copy link
Copy Markdown
Collaborator

@raman325 raman325 commented Apr 11, 2026

Proposed change

When a lock entry is deleted, delete_coordinator() removes hass.data[DOMAIN] after a 20-second delay. If the user creates a new lock entry before or after that cleanup fires, async_setup_services() crashes with KeyError because it assumes hass.data[DOMAIN] exists.

Two fixes applied:

  1. services.py — Added hass.data.setdefault(DOMAIN, {}) before accessing hass.data[DOMAIN], so the dict is recreated if it was previously removed.

  2. __init__.py — Added a guard in delete_coordinator() to skip domain data removal if new config entries already exist (handles the race condition where the 20-second delayed cleanup fires after a new entry is set up).

Type of change

  • Bugfix (non-breaking change which fixes an issue)

Additional information

🤖 Generated with Claude Code

raman325 and others added 4 commits March 10, 2026 23:20
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* upstream/main:
  chore: bump minimum HA version to 2026.4.0
  fix: stop re-fetching masked usercodes every poll cycle
  feat: add Schlage WiFi lock provider
  fix: auto-dismiss retry lock notifications when lock succeeds
  feat: add Last Used event entity per code slot
  fix: slugify lock name when generating default notification script name
  fix(tests): restore accidentally merged test_get_code_empty_pin
  fix(akuvox): handle X916 user filtering where source_type is None
  test: add tests for `_update_lock_data` early exit conditions
  test: add coverage for reset_code_slot, update_slot_active_state, and _update_child_code_slots
  feat: add Akuvox lock provider with event routing fixes
  style: move imports to module level to fix ruff PLC0415
  feat: Add auto-lock timer sensor with dashboard badge (FutureTense#509)
  test: add ping_node tests for ZWaveJS and base provider
  feat: ping dead node on first failure to attempt recovery
  style: apply ruff formatting fixes and add dead-node backoff tests
  fix: relax dead-node checks on connect/read operations
  fix: skip Z-Wave commands to dead nodes and add exponential backoff
When a lock entry is deleted, delete_coordinator() removes hass.data[DOMAIN]
after a 20-second delay. If a new lock entry is then created,
async_setup_services() crashes with KeyError accessing hass.data[DOMAIN].

Two fixes applied:
- Use hass.data.setdefault() in async_setup_services to handle missing key
- Guard delete_coordinator to skip removal if new config entries exist

Fixes FutureTense#593

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 11, 2026 01:48
@github-actions github-actions bot added the bugfix Fixes a bug label Apr 11, 2026
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 11, 2026

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 66.66667% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 90.06%. Comparing base (cdb4922) to head (551d48c).
⚠️ Report is 75 commits behind head on main.

Files with missing lines Patch % Lines
custom_components/keymaster/__init__.py 50.00% 1 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #595      +/-   ##
==========================================
+ Coverage   84.14%   90.06%   +5.91%     
==========================================
  Files          10       28      +18     
  Lines         801     3471    +2670     
==========================================
+ Hits          674     3126    +2452     
- Misses        127      345     +218     
Flag Coverage Δ
python 90.06% <66.66%> (?)

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

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a race condition in the Keymaster Home Assistant integration where hass.data[DOMAIN] could be removed after deleting the last config entry, causing a KeyError during subsequent lock setup (issue #593).

Changes:

  • Ensure async_setup_services() recreates hass.data[DOMAIN] when missing to prevent KeyError.
  • Guard delayed coordinator cleanup so it won’t remove domain data if new config entries already exist.
  • Update/add tests for the hass.data[DOMAIN]-missing scenario, and add new strategy-config-validation plan/design docs.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
custom_components/keymaster/services.py Recreates hass.data[DOMAIN] defensively before accessing it.
custom_components/keymaster/__init__.py Prevents delayed cleanup from removing domain data when entries exist (race guard).
tests/test_services.py Adds coverage to ensure async_setup_services works when the domain key was popped.
tests/test_init.py Adjusts a test that previously relied on the KeyError behavior (now fixed).
docs/plans/2026-03-10-strategy-config-validation.md Adds a large implementation plan document (appears unrelated to this bugfix PR).
docs/plans/2026-03-10-strategy-config-validation-design.md Adds a design doc for the same strategy-validation work (also appears unrelated here).

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

raman325 and others added 7 commits April 10, 2026 21:52
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address review feedback: use new_callable=AsyncMock instead of
return_value=None to avoid TypeError from awaiting None.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pass the unloaded config entry ID to delete_coordinator so it can
filter it out of async_entries(). This prevents the entry being
unloaded from counting as an active entry, which would incorrectly
block coordinator cleanup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Fixes a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ISSUE: Python KeyError during lock setup

3 participants