PrefectHQ/fastmcp · error · DeviceAuthorizationError

Device authorization failed

Error message

Device authorization failed

What it means

The fallback branch of poll_device_authorization: any unrecognized error string from the token exchange (not authorization_pending, slow_down, access_denied, or expired_token) raises the generic DeviceAuthorizationError('Device authorization failed').

Source

Thrown at fastmcp_slim/fastmcp/cli/deploy/authentication.py:74

        result = await client.exchange_device_authorization(authorization.device_code)
        if result.access_token is not None:
            return result.access_token
        if result.error == "authorization_pending":
            continue
        if result.error == "slow_down":
            interval += 5
            continue
        if result.error == "access_denied":
            raise DeviceAuthorizationDeniedError(
                "The device authorization request was denied"
            )
        if result.error == "expired_token":
            raise DeviceAuthorizationExpiredError(
                "The device authorization request expired"
            )

        raise DeviceAuthorizationError("Device authorization failed")


async def authorize_device(
    client: HorizonClient,
    *,
    metadata: DeviceMetadata | None = None,
    on_challenge: Callable[[DeviceAuthorization], None] | None = None,
    open_browser: bool = False,
    browser_opener: Callable[[str], object] = webbrowser.open,
    sleep: Callable[[float], Awaitable[None]] | None = None,
    monotonic: Callable[[], float] = time.monotonic,
) -> SecretStr:
    """Create, present, and complete a Horizon device authorization."""
    authorization = await client.create_device_authorization(metadata)
    if on_challenge is not None:
        on_challenge(authorization)

    if open_browser:

View on GitHub (pinned to 1f02114297)

Solutions

  1. Log/print the raw error value returned by the token endpoint to identify the unknown code
  2. Upgrade fastmcp so poll_device_authorization understands newer device-flow error codes
  3. Check Horizon service status / network middleboxes that may alter error responses
  4. Retry the login flow with a fresh device authorization
Defensive patterns

Strategy: try-catch

Try / catch

from fastmcp.cli.deploy.authentication import DeviceAuthorizationError
try:
    token = await poll_device_authorization(client, authorization)
except DeviceAuthorizationError as e:
    logger.exception("Device authorization failed: %s", e)
    token = await authorize_device(client, metadata=metadata)

Prevention

When it happens

Trigger: client.exchange_device_authorization returns a result whose error is an unexpected/unknown code (e.g. new server-side error types, 'invalid_grant', or malformed error responses).

Common situations: Horizon server version introducing a new OAuth error code; proxy/gateway returning non-standard error bodies; bugs in a custom HorizonClient stub used in tests.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/a5593443faab898a. Report an issue: GitHub.