{"record":{"id":"d1531b627b4311c6","repo":"home-assistant/core","slug":"authentication-with-airpatrol-failed","errorCode":null,"errorMessage":"Authentication with AirPatrol failed","messagePattern":"Authentication with AirPatrol failed","errorType":"exception","errorClass":"ConfigEntryAuthFailed","httpStatus":null,"severity":"error","filePath":"homeassistant/components/airpatrol/coordinator.py","lineNumber":56,"sourceCode":"        try:\n            await self._setup_client()\n        except AirPatrolError as api_err:\n            raise UpdateFailed(\n                f\"Error communicating with AirPatrol API: {api_err}\"\n            ) from api_err\n\n    @override\n    async def _async_update_data(self) -> dict[str, dict[str, Any]]:\n        \"\"\"Update unit data from AirPatrol API.\"\"\"\n        return {unit_data[\"unit_id\"]: unit_data for unit_data in await self._get_data()}\n\n    async def _get_data(self, retry: bool = False) -> list[dict[str, Any]]:\n        \"\"\"Fetch data from API.\"\"\"\n        try:\n            return await self.api.get_data()\n        except AirPatrolAuthenticationError as auth_err:\n            if retry:\n                raise ConfigEntryAuthFailed(\n                    \"Authentication with AirPatrol failed\"\n                ) from auth_err\n            await self._update_token()\n            return await self._get_data(retry=True)\n        except AirPatrolError as err:\n            raise UpdateFailed(\n                f\"Error communicating with AirPatrol API: {err}\"\n            ) from err\n\n    async def _update_token(self) -> None:\n        \"\"\"Refresh the AirPatrol API client and update the access token.\"\"\"\n        session = async_get_clientsession(self.hass)\n        try:\n            self.api = await AirPatrolAPI.authenticate(\n                session,\n                self.config_entry.data[CONF_EMAIL],\n                self.config_entry.data[CONF_PASSWORD],\n            )","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/home-assistant/core/blob/58a3fdb3ea0538617f0a07efcfba6294de64fd59/homeassistant/components/airpatrol/coordinator.py#L38-L74","documentation":"ConfigEntryAuthFailed raised during AirPatrol data refresh when get_data() raises AirPatrolAuthenticationError twice: the first failure triggers a token refresh and a single retry, and if the retry also fails authentication, this error starts the re-auth flow with 'Authentication with AirPatrol failed'.","triggerScenarios":"Expired/revoked access token where _update_token() re-authenticates with stored email/password but the password is now wrong, the account was deleted/locked, or the refreshed token is immediately rejected again (retry=True path).","commonSituations":"Password changed in the AirPatrol app after setup, account deactivated, or API token semantics changed by the provider so refresh tokens never validate.","solutions":["Confirm the AirPatrol account email/password still work in the official app.","Complete the Home Assistant re-authentication prompt for the airpatrol entry.","If credentials are correct and it still fails, check for a library/API version mismatch and update the integration.","Check logs for the chained auth_err to see the API's rejection reason."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"def is_airpatrol_auth_failed(err: Exception) -> bool:\n    return isinstance(err, ConfigEntryAuthFailed) and \"AirPatrol\" in str(err)","tryCatchPattern":"try:\n    await coordinator.async_refresh()\nexcept ConfigEntryAuthFailed:\n    # both retries rejected: re-enter credentials via re-auth flow; retrying with the same token is futile\n    await hass.config_entries.async_reload(entry.entry_id)","preventionTips":["Keep the AirPatrol password stable or update the Home Assistant entry immediately after changes.","Treat a second consecutive auth failure as a credential problem, never as a transient network issue."],"tags":["home-assistant","airpatrol","authentication","token-refresh"],"backgroundTag":null,"analyzedSha":"58a3fdb3ea0538617f0a07efcfba6294de64fd59","analyzedAt":"2026-08-14T20:54:38.818Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}