home-assistant/core · error · InvalidUsername
username_not_normalized
username_not_normalized
Error message
username_not_normalized
What it means
InvalidUsername with translation_key username_not_normalized, raised by Data._validate_new_username (homeassistant/auth/providers/homeassistant.py:254) when the proposed username differs from its force-normalized form (username.strip().casefold()). The provider refuses to store names with leading/trailing whitespace or uppercase letters so lookups stay deterministic; the offending value is passed as the new_username placeholder.
Source
Thrown at homeassistant/auth/providers/homeassistant.py:254
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")
@callback
def _validate_new_username(self, new_username: str) -> None:
"""Validate that username is normalized and unique.
Raises InvalidUsername if the new username is invalid.
"""
normalized_username = self.normalize_username(
new_username, force_normalize=True
)
if normalized_username != new_username:
raise InvalidUsername(
translation_key="username_not_normalized",
translation_placeholders={"new_username": new_username},
)
if any(
self.normalize_username(user["username"]) == normalized_username
for user in self.users
):
raise InvalidUsername(
translation_key="username_already_exists",
translation_placeholders={"username": new_username},
)
@callback
def change_username(self, username: str, new_username: str) -> None:
"""Update the username.
Raises InvalidUser if user cannot be found.View on GitHub (pinned to 58a3fdb3ea)
Solutions
- Normalize before calling: `username = username.strip().casefold()`
- Enforce trim + lowercase in the UI/form layer for new usernames
Example fix
// before
provider.data.add_auth("Bob", password) # raises username_not_normalized
# after
provider.data.add_auth("bob", password) Defensive patterns
Strategy: validation
Validate before calling
new_username = new_username.strip().casefold() provider.data.add_auth(new_username, password)
Type guard
def is_normalized(username: str) -> bool:
return username == username.strip().casefold() Try / catch
from homeassistant.auth.providers.homeassistant import InvalidUsername
try:
provider.data.add_auth(username, password)
except InvalidUsername as err:
if err.translation_key != "username_not_normalized":
raise
provider.data.add_auth(username.strip().casefold(), password) Prevention
- Apply strip().casefold() to every new username before submit
- Enforce trimming and lowercase in form validation layers
- Note legacy-mode stores may hold non-normalized names — address the repair issue first
When it happens
Trigger: Calling add_auth or change_username with e.g. " Alice ", "Bob", or any mixed-case/whitespace name; usernames sourced from external directories that preserve case.
Common situations: Programmatic user creation using display names; migrating old user lists; input from forms that don't trim/casefold before submission.
Related errors
- username_already_exists
- user_not_found
- 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/8e643fdc61653600.
Report an issue: GitHub.