Devolutions/UniGetUI · warning · InvalidOperationException
GitHub did not return an access token.
Error message
GitHub did not return an access token.
What it means
In CompleteGitHubDeviceFlowAsync, after calling CreateAccessTokenForDeviceFlowAsync the returned GitHubOAuthToken's AccessToken is checked. If it is null or whitespace, an InvalidOperationException is thrown before any token is stored. This guards against GitHub returning a 200 with an empty or missing access_token field — which happens when the device authorization has not been completed by the user yet, or when the response shape is unexpected.
Source
Thrown at src/UniGetUI.Interface.IpcApi/IpcBackupApi.cs:227
{
ClearPendingGitHubDeviceFlow();
throw new InvalidOperationException(
"The pending GitHub device flow has expired. Start sign-in again."
);
}
try
{
using var client = CreateAnonymousGitHubClient();
var token = await client.CreateAccessTokenForDeviceFlowAsync(
Secrets.GetGitHubClientId(),
pending.DeviceFlow,
CancellationToken.None
);
if (string.IsNullOrWhiteSpace(token.AccessToken))
{
throw new InvalidOperationException("GitHub did not return an access token.");
}
SecureGHTokenManager.StoreToken(token.AccessToken);
using var userClient = CreateAuthenticatedGitHubClient(token.AccessToken);
var user = await userClient.GetCurrentUserAsync();
Settings.SetValue(Settings.K.GitHubUserLogin, user.Login ?? string.Empty);
ClearPendingGitHubDeviceFlow();
return new IpcGitHubAuthResult
{
Status = "success",
Command = "complete-github-sign-in",
Message = string.IsNullOrWhiteSpace(user.Login)
? "GitHub sign-in completed."
: $"GitHub sign-in completed for {user.Login}.",
Auth = await GetGitHubAuthInfoAsync(),
};
}View on GitHub (pinned to 9b1d7d0eab)
Solutions
- Ensure the user has completed the browser authorization before calling CompleteGitHubDeviceFlowAsync.
- Poll at the device-flow interval and only complete once authorization is confirmed.
- If this persists, restart the device flow (StartGitHubDeviceFlowAsync) and have the user re-authorize.
Example fix
// before: completing before the user finishes authorization
await IpcBackupApi.CompleteGitHubDeviceFlowAsync();
// after: poll until the user has authorized, then complete
var auth = await IpcBackupApi.GetStatusAsync();
if (auth.Auth.IsAuthenticated || /* user confirmed browser approval */ true)
await IpcBackupApi.CompleteGitHubDeviceFlowAsync(); Defensive patterns
Strategy: retry
Try / catch
try { await IpcBackupApi.CompleteGitHubDeviceFlowAsync(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("did not return an access token"))
{ /* user has not finished browser auth yet; poll again or restart flow */ } Prevention
- Only call CompleteGitHubDeviceFlowAsync after the user confirms browser authorization.
- Poll at the device-flow interval to avoid premature token requests.
- Restart the device flow if authorization cannot be completed in time.
When it happens
Trigger: The user has not yet entered the device code in the browser, or has not approved the authorization, but the token endpoint was polled and returned a body without an access_token (e.g. an 'authorization_pending' error serialized as 200, or a malformed response).
Common situations: The client polls the token endpoint before the user finishes browser authorization. GitHub returns an error descriptor (e.g. {"error":"authorization_pending"}) that deserializes into a token with an empty AccessToken. A network proxy returns an empty 200. The device code was already used or expired and GitHub returns a non-token body.
Related errors
- The pending GitHub device flow has expired. Start sign-in ag
- GitHub sign-in did not complete successfully. Finish the dev
- No GitHub device flow is pending. Start sign-in first.
- GitHub authentication is required for cloud backups.
- GitHub sign-in is not configured for this build. UNIGETUI_GI
AI-assisted analysis of Devolutions/UniGetUI@9b1d7d0eab (2026-08-13).
Data as JSON: /api/errors/95c49ee9069ef62c.
Report an issue: GitHub.