home-assistant/core · error · ValueError

Credential is already linked to a user

Error message

Credential is already linked to a user

What it means

ConfigEntryNotReady is Home Assistant's signal that a config entry could not be set up because a dependency (here the Bosch Smart Home Controller) was unreachable. In bosch_shc it is raised from SHCConnectionError while constructing the SHCSession, telling the config entry machinery to retry setup later instead of failing permanently. The coordinator pattern keeps the entry in a 'setup in progress/retry' state with exponential backoff.

Source

Thrown at homeassistant/auth/__init__.py:341

            name=info.name,
            is_active=info.is_active,
            group_ids=[GROUP_ID_ADMIN if info.group is None else info.group],
            local_only=info.local_only,
        )

        self.hass.bus.async_fire(EVENT_USER_ADDED, {"user_id": user.id})

        return user

    async def async_link_user(
        self, user: models.User, credentials: models.Credentials
    ) -> None:
        """Link credentials to an existing user."""
        linked_user = await self.async_get_user_by_credentials(credentials)
        if linked_user == user:
            return
        if linked_user is not None:
            raise ValueError("Credential is already linked to a user")

        await self._store.async_link_user(user, credentials)

    async def async_remove_user(self, user: models.User) -> None:
        """Remove a user."""
        tasks = [
            self.async_remove_credentials(credentials)
            for credentials in user.credentials
        ]

        if tasks:
            await asyncio.gather(*tasks)

        await self._store.async_remove_user(user)

        self.hass.bus.async_fire(EVENT_USER_REMOVED, {"user_id": user.id})

    async def async_update_user(

View on GitHub (pinned to 58a3fdb3ea)

Solutions

  1. Verify the Bosch Smart Home Controller is powered on and reachable: ping the host / open https://<host>:8444 in a browser from the same machine running HA.
  2. Check the configured host in the config entry still matches the controller's current IP (or relies on freshly discovered zeroconf info); re-run discovery or update the host.
  3. Confirm the SSL certificate and key files referenced by CONF_SSL_CERTIFICATE/CONF_SSL_KEY still exist and match the controller's current cert (re-pair via the Bosch app if needed).
  4. If the error persists, enable debug logging for bosch_shc and check the underlying SHCConnectionError message; HA will keep retrying with backoff, so a transient outage self-heals once connectivity returns.

Example fix

// No code fix — this is a setup-time connectivity signal. But ensure transient
// errors surface as NotReady rather than a hard failure:
try:
    session = await hass.async_add_executor_job(
        SHCSession, data[CONF_HOST], data[CONF_SSL_CERTIFICATE],
        data[CONF_SSL_KEY], False, zeroconf,
    )
except SHCConnectionError as err:
    raise ConfigEntryNotReady from err  # HA retries setup automatically
// If you control the caller and the host may change, refresh it first:
// entry.async_update_hass_config(hass, {**entry.data, CONF_HOST: new_ip})
Defensive patterns

Strategy: retry

Validate before calling

# Before setup, probe reachability of the controller
import socket, ssl

def host_reachable(host: str, port: int = 8444, timeout: float = 3.0) -> bool:
    try:
        with socket.create_connection((host, port), timeout=timeout):
            return True
    except OSError:
        return False

Type guard

# Not applicable — Python duck-typed integration; guard on exception type instead
assert isinstance(err, SHCConnectionError)  # narrow before converting to ConfigEntryNotReady

Try / catch

try:
    session = await hass.async_add_executor_job(SHCSession, host, cert, key, False, zeroconf)
except SHCAuthenticationError as err:
    raise ConfigEntryAuthFailed from err   # credential problem -> reauth
except SHCConnectionError as err:
    raise ConfigEntryNotReady from err      # transient -> retry with backoff

Prevention

When it happens

Trigger: Creating an SHCSession (hass.async_add_executor_job(SHCSession, host, ssl_cert, ssl_key, False, zeroconf)) throws SHCConnectionError — the HTTP/WebSocket connection to the Bosch SHC box at data[CONF_HOST] cannot be established (device offline, wrong IP, TLS handshake failure, or mDNS/zeroconf info stale).

Common situations: Controller powered off or rebooting (e.g. after a firmware update), router DHCP changed the SHC IP while the config still pins the old host, self-signed certificate/key mismatch after re-pairing, or firewall/VLAN blocking port 8444/8084 to the controller.

Related errors


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