home-assistant/core · error · InvalidUsername

username_already_exists

username_already_exists

Error message

username_already_exists

What it means

InvalidUsername with translation_key username_already_exists, raised by Data._validate_new_username (homeassistant/auth/providers/homeassistant.py:263) when the normalized new username equals an existing stored username (comparison is done on normalized forms, so 'Bob' collides with 'bob'). The placeholder username carries the rejected value.

Source

Thrown at homeassistant/auth/providers/homeassistant.py:263

    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.
        Raises InvalidUsername if the new username is invalid.
        """
        username = self.normalize_username(username)
        self._validate_new_username(new_username)

        for user in self.users:
            if self.normalize_username(user["username"]) == username:
                user["username"] = new_username
                assert self._data is not None

View on GitHub (pinned to 58a3fdb3ea)

Solutions

  1. Before creating, check `any(provider.data.normalize_username(u["username"]) == new_username.strip().casefold() for u in provider.data.users)` and skip
  2. For renames, first verify the target name is free; for imports, deduplicate names before writing

Example fix

// before
provider.data.add_auth("alice", password)  # alice exists

# after
normalized = "alice"
if not any(provider.data.normalize_username(u["username"]) == normalized for u in provider.data.users):
    provider.data.add_auth(normalized, password)
Defensive patterns

Strategy: validation

Validate before calling

normalized = new_username.strip().casefold()
if not any(provider.data.normalize_username(u["username"]) == normalized for u in provider.data.users):
    provider.data.add_auth(new_username, password)

Type guard

def username_is_unique(provider_data, new_username: str) -> bool:
    normalized = new_username.strip().casefold()
    return not any(
        provider_data.normalize_username(u["username"]) == normalized
        for u in provider_data.users
    )

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_already_exists":
        raise
    # pick a different name or return the existing account

Prevention

When it happens

Trigger: add_auth with a name already in the store; change_username to a name owned by another account; migration scripts re-creating existing users.

Common situations: Idempotent provisioning scripts that don't check first; renames colliding with another user; imports merging two sources with duplicate names.

Related errors


AI-assisted analysis of home-assistant/core@58a3fdb3ea (2026-08-14). Data as JSON: /api/errors/2dc53bc23fb26b09. Report an issue: GitHub.