home-assistant/core · error · InvalidUser
user_not_found
user_not_found
Error message
user_not_found
What it means
InvalidUser with translation_key user_not_found, raised by Data.async_remove_auth (homeassistant/auth/providers/homeassistant.py:226) when the username to delete does not exist in the local auth provider's user store. Usernames are normalized (strip + casefold) before lookup, so only a truly absent (or differently spelled-but-normalizing-equal) name passes.
Source
Thrown at homeassistant/auth/providers/homeassistant.py:226
{
"username": username,
"password": self.hash_password(password, True).decode(),
}
)
@callback
def async_remove_auth(self, username: str) -> None:
"""Remove authentication."""
username = self.normalize_username(username)
index = None
for i, user in enumerate(self.users):
if self.normalize_username(user["username"]) == username:
index = i
break
if index is None:
raise InvalidUser(translation_key="user_not_found")
self.users.pop(index)
def change_password(self, username: str, new_password: str) -> None:
"""Update the password.
Raises InvalidUser if user cannot be found.
"""
username = self.normalize_username(username)
for user in self.users:
if self.normalize_username(user["username"]) == username:
user["password"] = self.hash_password(new_password, True).decode()
break
else:
raise InvalidUser(translation_key="user_not_found")
@callbackView on GitHub (pinned to 58a3fdb3ea)
Solutions
- Check membership first: `if all(prv.normalize_username(u['username']) != provider.data.normalize_username(username) for u in provider.data.users): skip` — or simply treat user_not_found as success (idempotent delete)
- Catch InvalidUser and inspect translation_key == 'user_not_found' to tolerate double-delete
Example fix
// before
provider.data.async_remove_auth(username) # raises if absent
# after
from homeassistant.auth.providers.homeassistant import InvalidUser
try:
provider.data.async_remove_auth(username)
except InvalidUser as err:
if err.translation_key != "user_not_found":
raise Defensive patterns
Strategy: try-catch
Validate before calling
normalized = provider.normalize_username(username)
exists = any(
provider.normalize_username(u["username"]) == normalized
for u in provider.data.users
)
if exists:
provider.data.async_remove_auth(username) Try / catch
from homeassistant.auth.providers.homeassistant import InvalidUser
try:
provider.data.async_remove_auth(username)
except InvalidUser as err:
if err.translation_key != "user_not_found":
raise
# already gone: nothing to do Prevention
- Treat removal as idempotent: user_not_found on delete is success
- Always use the provider's own username list as source of truth
When it happens
Trigger: Calling provider.data.async_remove_auth(username) for a name not in the storage; name already removed by a prior call; passing the HA user name instead of the provider username.
Common situations: Onboarding/offboarding scripts deleting an already-deleted account; mismatch between auth provider usernames and user-facing names; concurrent deletion flows.
Related errors
- username_not_normalized
- username_already_exists
- User is not active
- System generated users cannot have refresh tokens connected
- System generated users can only have system type refresh tok
AI-assisted analysis of home-assistant/core@58a3fdb3ea (2026-08-14).
Data as JSON: /api/errors/b46b43253e0f2105.
Report an issue: GitHub.