home-assistant/core · error · ValueError
Client is required to generate a refresh token.
Error message
Client is required to generate a refresh token.
What it means
Thrown by AuthManager.async_create_refresh_token (homeassistant/auth/__init__.py:488) when token_type is TOKEN_TYPE_NORMAL but client_id is None. Normal (short-lived, refreshable) tokens are always bound to the OAuth client that requested them, so a client_id is mandatory.
Source
Thrown at homeassistant/auth/__init__.py:488
if token_type is None:
if user.system_generated:
token_type = models.TOKEN_TYPE_SYSTEM
else:
token_type = models.TOKEN_TYPE_NORMAL
if token_type is models.TOKEN_TYPE_NORMAL:
expire_at = time.time() + REFRESH_TOKEN_EXPIRATION
else:
expire_at = None
if user.system_generated != (token_type == models.TOKEN_TYPE_SYSTEM):
raise ValueError(
"System generated users can only have system type refresh tokens"
)
if token_type == models.TOKEN_TYPE_NORMAL and client_id is None:
raise ValueError("Client is required to generate a refresh token.")
if (
token_type == models.TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN
and client_name is None
):
raise ValueError("Client_name is required for long-lived access token")
if token_type == models.TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN:
for token in user.refresh_tokens.values():
if (
token.client_name == client_name
and token.token_type == models.TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN
):
# Each client_name can only have one
# long_lived_access_token type of refresh token
raise ValueError(f"{client_name} already exists")
return await self._store.async_create_refresh_token(View on GitHub (pinned to 58a3fdb3ea)
Solutions
- Pass the client_id of the requesting client: `await hass.auth.async_create_refresh_token(user, client_id)`
- If you intend a long-lived token, pass token_type=models.TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN together with a client_name instead
Example fix
// before refresh_token = await hass.auth.async_create_refresh_token(user, client_id=None) # after refresh_token = await hass.auth.async_create_refresh_token(user, client_id="https://my.example.app")
Defensive patterns
Strategy: validation
Validate before calling
if token_type == models.TOKEN_TYPE_NORMAL:
assert client_id is not None
await hass.auth.async_create_refresh_token(user, client_id=client_id) Type guard
def has_required_client(token_type, client_id) -> bool:
return token_type is not models.TOKEN_TYPE_NORMAL or client_id is not None Prevention
- Forward the client_id from the auth flow step data whenever issuing normal tokens
- If you need a token without a client, create a long-lived access token with a client_name instead
When it happens
Trigger: Calling async_create_refresh_token(user) or with client_id=None while token_type stays TOKEN_TYPE_NORMAL (the default for non-system users).
Common situations: Test code minting tokens without a client; scripts forgetting to forward the client_id from the auth flow step data; using long-lived-token style calls (no client_id) but leaving token_type at its default.
Related errors
- User is not active
- System generated users cannot have refresh tokens connected
- System generated users can only have system type refresh tok
- Client_name is required for long-lived access token
- {client_name} already exists
AI-assisted analysis of home-assistant/core@58a3fdb3ea (2026-08-14).
Data as JSON: /api/errors/2f25758cfef80773.
Report an issue: GitHub.