Devolutions/UniGetUI · error · InvalidOperationException

GitHub sign-in did not complete successfully. Finish the dev

Error message

GitHub sign-in did not complete successfully. Finish the device authorization and try again.

What it means

CompleteGitHubDeviceFlowAsync wraps the token-exchange and user-fetch logic in a try/catch (Exception). If any exception occurs inside the try block — HttpRequestException from the token endpoint, the empty-token InvalidOperationException, an error from GetCurrentUserAsync, or a SecureGHTokenManager failure — it is logged and re-thrown as a new InvalidOperationException with this generic message. The original exception's type and detail are lost to the caller (only logged).

Source

Thrown at src/UniGetUI.Interface.IpcApi/IpcBackupApi.cs:250

            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(),
            };
        }
        catch (Exception ex)
        {
            Logger.Error("An error occurred while completing GitHub device flow sign-in:");
            Logger.Error(ex);
            throw new InvalidOperationException(
                "GitHub sign-in did not complete successfully. Finish the device authorization and try again."
            );
        }
    }

    public static async Task<IpcGitHubAuthResult> SignOutGitHubAsync()
    {
        Settings.SetValue(Settings.K.GitHubUserLogin, "");
        SecureGHTokenManager.DeleteToken();
        ClearPendingGitHubDeviceFlow();

        return new IpcGitHubAuthResult
        {
            Status = "success",
            Command = "sign-out-github",
            Message = "GitHub sign-out complete.",
            Auth = await GetGitHubAuthInfoAsync(),
        };

View on GitHub (pinned to 9b1d7d0eab)

Solutions

  1. Check the application logs (Logger.Error output) for the original exception that was swallowed — the re-thrown message is generic.
  2. Retry the complete flow; most causes (network, timing) are transient.
  3. Restart the device flow (StartGitHubDeviceFlowAsync) if retries fail, in case the device code or token is stale.
  4. Verify network connectivity and that UNIGETUI_GITHUB_CLIENT_ID is correctly configured.
Defensive patterns

Strategy: try-catch

Try / catch

try { await IpcBackupApi.CompleteGitHubDeviceFlowAsync(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("did not complete successfully"))
{ /* inspect logs for the original swallowed exception; restart the flow */ }

Prevention

When it happens

Trigger: Any exception is thrown within the try block of CompleteGitHubDeviceFlowAsync: network failure contacting GitHub, expired/revoked token, empty access token, failure to fetch the current user, or an error storing the token securely. The catch-all wraps all of these into a single generic message.

Common situations: Transient network error during token exchange. The user did not complete authorization and the token endpoint returned an error. The stored token was invalid. GetCurrentUserAsync failed with 401/403. The original root cause must be found in the logs (Logger.Error) since the re-thrown exception does not preserve it as InnerException.

Related errors


AI-assisted analysis of Devolutions/UniGetUI@9b1d7d0eab (2026-08-13). Data as JSON: /api/errors/00e568a07c49c19b. Report an issue: GitHub.