Devolutions/UniGetUI · warning · InvalidOperationException
No GitHub device flow is pending. Start sign-in first.
Error message
No GitHub device flow is pending. Start sign-in first.
What it means
GetPendingGitHubDeviceFlow (called by CompleteGitHubDeviceFlowAsync) reads the static _pendingGitHubDeviceFlow field under a lock. If it is null — no device flow was ever started, or the previous one was cleared by expiry/sign-out — it throws InvalidOperationException. This is a precondition check: the completion step requires a prior initiation step.
Source
Thrown at src/UniGetUI.Interface.IpcApi/IpcBackupApi.cs:572
return PackageBackupStartingKey + " " + deviceUser;
}
private static string ValidateBackupKey(string key)
{
if (string.IsNullOrWhiteSpace(key))
{
throw new InvalidOperationException("The backup key is required.");
}
return key;
}
private static PendingGitHubDeviceFlow GetPendingGitHubDeviceFlow()
{
lock (GitHubAuthLock)
{
return _pendingGitHubDeviceFlow
?? throw new InvalidOperationException(
"No GitHub device flow is pending. Start sign-in first."
);
}
}
private static void ClearPendingGitHubDeviceFlow()
{
lock (GitHubAuthLock)
{
_pendingGitHubDeviceFlow = null;
}
}
}
View on GitHub (pinned to 9b1d7d0eab)
Solutions
- Always call StartGitHubDeviceFlowAsync before CompleteGitHubDeviceFlowAsync.
- Check IpcGitHubAuthInfo.DeviceFlowPending (via GetStatusAsync) before attempting completion.
- If the flow was cleared by expiry or restart, start a new one.
- Ensure start and complete happen in the same process/session, since the pending flow is in-memory only.
Example fix
// before: completing without starting
await IpcBackupApi.CompleteGitHubDeviceFlowAsync();
// after: start first, then complete
var status = await IpcBackupApi.GetStatusAsync();
if (!status.Auth.DeviceFlowPending)
await IpcBackupApi.StartGitHubDeviceFlowAsync(new IpcGitHubDeviceFlowRequest { LaunchBrowser = true });
await IpcBackupApi.CompleteGitHubDeviceFlowAsync(); Defensive patterns
Strategy: validation
Validate before calling
var status = await IpcBackupApi.GetStatusAsync();
if (!status.Auth.DeviceFlowPending)
await IpcBackupApi.StartGitHubDeviceFlowAsync(new IpcGitHubDeviceFlowRequest { LaunchBrowser = true }); Type guard
static bool HasPendingDeviceFlow(IpcGitHubAuthInfo auth) => auth.DeviceFlowPending;
Try / catch
try { await IpcBackupApi.CompleteGitHubDeviceFlowAsync(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("No GitHub device flow is pending"))
{ await IpcBackupApi.StartGitHubDeviceFlowAsync(new IpcGitHubDeviceFlowRequest { LaunchBrowser = true }); } Prevention
- Always start the device flow before completing it.
- Check DeviceFlowPending before calling complete.
- Keep start and complete in the same process — the pending state is in-memory.
When it happens
Trigger: CompleteGitHubDeviceFlowAsync is called without a preceding successful StartGitHubDeviceFlowAsync. Or the pending flow was already cleared by: expiry (CompleteGitHubDeviceFlowAsync itself clears it on timeout), sign-out (SignOutGitHubAsync), or GetGitHubAuthInfoAsync's auto-clear on expiry. In a multi-daemon scenario, the pending flow lives in a different process's static field.
Common situations: The client calls complete before start. The flow expired and was auto-cleared by a status check. The user signed out between start and complete. A second process/session is involved (the static field is per-process). The app restarted, losing the in-memory pending flow.
Related errors
- The pending GitHub device flow has expired. Start sign-in ag
- GitHub did not return an access token.
- GitHub sign-in did not complete successfully. Finish the dev
- GitHub sign-in is not configured for this build. UNIGETUI_GI
- GitHub authentication is required for cloud backups.
AI-assisted analysis of Devolutions/UniGetUI@9b1d7d0eab (2026-08-13).
Data as JSON: /api/errors/6d84f22d06c17fd2.
Report an issue: GitHub.