{"record":{"id":"a5593443faab898a","repo":"PrefectHQ/fastmcp","slug":"device-authorization-failed","errorCode":null,"errorMessage":"Device authorization failed","messagePattern":"Device authorization failed","errorType":"exception","errorClass":"DeviceAuthorizationError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/cli/deploy/authentication.py","lineNumber":74,"sourceCode":"\n        result = await client.exchange_device_authorization(authorization.device_code)\n        if result.access_token is not None:\n            return result.access_token\n        if result.error == \"authorization_pending\":\n            continue\n        if result.error == \"slow_down\":\n            interval += 5\n            continue\n        if result.error == \"access_denied\":\n            raise DeviceAuthorizationDeniedError(\n                \"The device authorization request was denied\"\n            )\n        if result.error == \"expired_token\":\n            raise DeviceAuthorizationExpiredError(\n                \"The device authorization request expired\"\n            )\n\n        raise DeviceAuthorizationError(\"Device authorization failed\")\n\n\nasync def authorize_device(\n    client: HorizonClient,\n    *,\n    metadata: DeviceMetadata | None = None,\n    on_challenge: Callable[[DeviceAuthorization], None] | None = None,\n    open_browser: bool = False,\n    browser_opener: Callable[[str], object] = webbrowser.open,\n    sleep: Callable[[float], Awaitable[None]] | None = None,\n    monotonic: Callable[[], float] = time.monotonic,\n) -> SecretStr:\n    \"\"\"Create, present, and complete a Horizon device authorization.\"\"\"\n    authorization = await client.create_device_authorization(metadata)\n    if on_challenge is not None:\n        on_challenge(authorization)\n\n    if open_browser:","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/cli/deploy/authentication.py#L56-L92","documentation":"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').","triggerScenarios":"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).","commonSituations":"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.","solutions":["Log/print the raw error value returned by the token endpoint to identify the unknown code","Upgrade fastmcp so poll_device_authorization understands newer device-flow error codes","Check Horizon service status / network middleboxes that may alter error responses","Retry the login flow with a fresh device authorization"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"from fastmcp.cli.deploy.authentication import DeviceAuthorizationError\ntry:\n    token = await poll_device_authorization(client, authorization)\nexcept DeviceAuthorizationError as e:\n    logger.exception(\"Device authorization failed: %s\", e)\n    token = await authorize_device(client, metadata=metadata)","preventionTips":["Keep fastmcp updated so new device-flow error codes are recognized","Inspect raw token-endpoint responses when using a custom HorizonClient","Retry the flow once before escalating; unknown errors are often transient"],"tags":["oauth","device-flow","unknown-error"],"backgroundTag":"device-flow-failed","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}