[codex] Handle retryable SleepIQ login failures#168522
[codex] Handle retryable SleepIQ login failures#168522anderbak wants to merge 3 commits intohome-assistant:devfrom
Conversation
|
Hey there @mfugate1, @kbickar, mind taking a look at this pull request as it has been labeled with an integration ( Code owner commandsCode owners of
|
There was a problem hiding this comment.
Pull request overview
This PR updates the SleepIQ integration’s error mapping so only truly invalid credentials trigger invalid_auth/reauth, while other SleepIQLoginException login failures are treated as retryable connection failures.
Changes:
- Add logic to classify
SleepIQLoginException("Incorrect username or password")as invalid auth, and treat other login exceptions as connection issues (retryable during setup;cannot_connectin config flow). - Update config entry setup to raise
ConfigEntryNotReadyfor retryable login exceptions instead ofConfigEntryAuthFailed. - Add regression tests covering setup retry vs setup error, and config flow invalid auth vs cannot connect.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
homeassistant/components/sleepiq/__init__.py |
Distinguishes invalid-credential login failures from retryable login failures during config entry setup. |
homeassistant/components/sleepiq/config_flow.py |
Updates try_connection to map only the credential error to invalid_auth, other login failures to cannot_connect. |
tests/components/sleepiq/test_init.py |
Adds tests asserting SETUP_ERROR for invalid auth and SETUP_RETRY for retryable login failures/timeouts. |
tests/components/sleepiq/test_config_flow.py |
Adds parametrized coverage for invalid auth vs cannot connect on login failures. |
| def _is_invalid_auth(err: SleepIQLoginException) -> bool: | ||
| """Return if a SleepIQ login exception indicates invalid credentials.""" | ||
| return "incorrect username or password" in str(err).lower() | ||
|
|
There was a problem hiding this comment.
Centralize the invalid-auth detection logic in a single shared helper/constant (e.g., in const.py or a small util module) to avoid the duplicated _is_invalid_auth implementation diverging between __init__.py and config_flow.py over time.
|
|
||
|
|
||
| def _is_invalid_auth(err: SleepIQLoginException) -> bool: | ||
| """Return if a SleepIQ login exception indicates invalid credentials.""" | ||
| return "incorrect username or password" in str(err).lower() |
There was a problem hiding this comment.
Avoid duplicating _is_invalid_auth in multiple modules; move the credential-error string match into a shared helper/constant so config flow and entry setup stay consistent if the upstream error text ever changes.
| def _is_invalid_auth(err: SleepIQLoginException) -> bool: | |
| """Return if a SleepIQ login exception indicates invalid credentials.""" | |
| return "incorrect username or password" in str(err).lower() | |
| _INVALID_AUTH_ERROR = "incorrect username or password" | |
| def _is_invalid_auth(err: SleepIQLoginException) -> bool: | |
| """Return if a SleepIQ login exception indicates invalid credentials.""" | |
| return _INVALID_AUTH_ERROR in str(err).lower() |
| await gateway.login(user_input[CONF_USERNAME], user_input[CONF_PASSWORD]) | ||
| except SleepIQLoginException: | ||
| return "invalid_auth" | ||
| except SleepIQLoginException as err: | ||
| if _is_invalid_auth(err): | ||
| return "invalid_auth" | ||
| return "cannot_connect" | ||
| except SleepIQTimeoutException: |
There was a problem hiding this comment.
Add regression coverage for the reauth flow’s failure cases since try_connection now maps SleepIQLoginException to either invalid_auth or cannot_connect and reauth uses the same helper.
| @pytest.mark.parametrize( | ||
| ("side_effect", "error"), | ||
| [ | ||
| ( | ||
| SleepIQLoginException("Incorrect username or password"), | ||
| "invalid_auth", | ||
| ), | ||
| ( | ||
| SleepIQLoginException("Connection failure: Cannot connect to host"), | ||
| "cannot_connect", | ||
| ), | ||
| (SleepIQTimeoutException, "cannot_connect"), | ||
| ], |
There was a problem hiding this comment.
Reduce duplicated parametrization data by extracting the shared (side_effect, error) cases into a single constant/fixture and reusing it in both test_login_failure and test_reauth_failure to keep future updates in sync.
Summary
SleepIQLoginException("Incorrect username or password")as invalid authSleepIQLoginExceptionvalues during setup and config flow as retryable connection failuresWhy
asyncsleepiqusesSleepIQLoginExceptionfor both real credential failures and transient login/connection failures such as:Connection failure: Cannot connect to host prod-api.sleepiq.sleepnumber.com:443 ssl:default [DNS server returned general failure]Home Assistant currently maps all of those exceptions to
invalid_auth/ reauth, which prompts users to re-enter valid credentials during transient provider or DNS outages.Impact
Transient SleepIQ login failures should now retry automatically instead of triggering reauth, while true bad credentials still surface as auth errors.
Testing
python -m py_compile homeassistant/components/sleepiq/__init__.py homeassistant/components/sleepiq/config_flow.py tests/components/sleepiq/test_init.py tests/components/sleepiq/test_config_flow.pycoredev requires Python 3.14.2+