{"record":{"id":"b4ac0c0a14e02b97","repo":"PrefectHQ/fastmcp","slug":"the-device-authorization-request-expired","errorCode":null,"errorMessage":"The device authorization request expired","messagePattern":"The device authorization request expired","errorType":"exception","errorClass":"DeviceAuthorizationExpiredError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/cli/deploy/authentication.py","lineNumber":47,"sourceCode":"    \"\"\"The device authorization request expired.\"\"\"\n\n\nasync def poll_device_authorization(\n    client: HorizonClient,\n    authorization: DeviceAuthorization,\n    *,\n    sleep: Callable[[float], Awaitable[None]] | None = None,\n    monotonic: Callable[[], float] = time.monotonic,\n) -> SecretStr:\n    \"\"\"Poll at the server interval until the device request completes.\"\"\"\n    sleep = asyncio.sleep if sleep is None else sleep\n    deadline = monotonic() + authorization.expires_in\n    interval = float(authorization.interval)\n\n    while True:\n        remaining = deadline - monotonic()\n        if remaining <= 0:\n            raise DeviceAuthorizationExpiredError(\n                \"The device authorization request expired\"\n            )\n\n        await sleep(min(interval, remaining))\n        if monotonic() >= deadline:\n            raise DeviceAuthorizationExpiredError(\n                \"The device authorization request expired\"\n            )\n\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\":","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/cli/deploy/authentication.py#L29-L65","documentation":"poll_device_authorization enforces a local deadline of authorization.expires_in seconds from the start of polling. If the deadline passes before the user approves the request, DeviceAuthorizationExpiredError('The device authorization request expired') is raised immediately before another poll.","triggerScenarios":"Calling poll_device_authorization (or authorize_device) when monotonic() indicates the local deadline has already elapsed, i.e. the user did not complete browser approval within expires_in seconds.","commonSituations":"The user left the verification URL open too long, never opened the browser, or a test injects a fake monotonic clock that has advanced past the deadline.","solutions":["Restart the flow: call authorize_device again to get a fresh device authorization with a new expires_in","Complete browser approval promptly after starting login","Increase the server-provided expires_in if you control the Horizon authorization server"],"exampleFix":"// before\ntoken = await poll_device_authorization(client, stale_authorization)  # expired\n// after\nauthorization = await client.create_device_authorization(metadata)\ntoken = await poll_device_authorization(client, authorization)","handlingStrategy":"try-catch","validationCode":"import time\nif authorization.expires_in <= 0:\n    raise RuntimeError(\"authorization already expired; request a new one\")","typeGuard":null,"tryCatchPattern":"from fastmcp.cli.deploy.authentication import DeviceAuthorizationExpiredError\ntry:\n    token = await poll_device_authorization(client, authorization)\nexcept DeviceAuthorizationExpiredError:\n    authorization = await client.create_device_authorization(metadata)\n    token = await poll_device_authorization(client, authorization)","preventionTips":["Open the browser automatically (open_browser=True) to reduce approval latency","Complete approval soon after login starts; restart if the prompt sits idle","Check expires_in from the DeviceAuthorization before starting long-running work"],"tags":["oauth","device-flow","timeout"],"backgroundTag":"device-flow-expired","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}