paperclipai/paperclip · error
Paperclip couldn’t preserve this sign-in while refreshing yo
Error message
Paperclip couldn’t preserve this sign-in while refreshing your account.
What it means
During OAuth reauthentication in ConnectionSetupFlow, after the cloud indicates a reauthentication flow, the code needs a destination (the dialog popup or the current window) plus a persisted handoff to carry session state. If the popup is missing, already closed, or the start result carries no handoff, the sign-in cannot be preserved across the account refresh, so the flow throws this user-facing error.
Source
Thrown at ui/src/features/connections/ConnectionSetupFlow.tsx:707
setOAuthError("The sign-in window closed. If authorization did not finish, try again.");
setAuthorizationFallbackUrl(null);
onPhaseChange?.("needs_retry");
}, 1_000);
return () => window.clearInterval(timer);
}, [host, oauthPhase, onPhaseChange]);
const prepareAndOpenOAuth = useCallback(async (
start: Pick<ToolOAuthStartResult, "authorizationUrl" | "handoff">,
) => {
oauthHandoffAbortRef.current?.abort();
const controller = new AbortController();
oauthHandoffAbortRef.current = controller;
try {
const target = await prepareOAuthNavigation(start, { signal: controller.signal });
if (target.kind === "reauthentication") {
const destination = host === "dialog" ? oauthPopupRef.current : window;
if (!destination || destination.closed || !start.handoff) {
throw new Error("Paperclip couldn’t preserve this sign-in while refreshing your account.");
}
savePendingCloudHandoff(start.handoff.session, destination.sessionStorage);
setOAuthPhase("starting");
} else {
setAuthorizationHost(target.host);
setOAuthPhase("redirecting");
}
openAuthorization(target.url);
} catch (error) {
if (controller.signal.aborted) return;
setOAuthPhase("error");
setOAuthError(error instanceof Error ? error.message : "Paperclip couldn’t start secure sign-in. Try again.");
onPhaseChange?.("needs_retry");
} finally {
if (oauthHandoffAbortRef.current === controller) oauthHandoffAbortRef.current = null;
}
}, [host, onPhaseChange, openAuthorization]);
View on GitHub (pinned to 01ad858492)
Solutions
- Allow popups for the Paperclip origin and restart the connection setup.
- Retry the connection flow in the same tab (non-dialog host) if popups cannot be enabled.
- Check the server response: if `handoff` is missing on a reauthentication start, fix the backend to return it.
Example fix
// before
const destination = host === "dialog" ? oauthPopupRef.current : window;
if (!destination || destination.closed || !start.handoff) throw new Error("...");
// after
if (host === "dialog" && (!oauthPopupRef.current || oauthPopupRef.current.closed)) {
reopenDialogAndRetry(start); // re-open popup instead of failing
return;
}
const destination = host === "dialog" ? oauthPopupRef.current : window; Defensive patterns
Strategy: try-catch
Validate before calling
function dialogReady(ref: React.RefObject<Window | null>): boolean {
return !!ref.current && !ref.current.closed;
} Type guard
function canPreserveSignIn(dest: Window | null, handoff: unknown): handoff is { session: string } {
return !!dest && !dest.closed && !!handoff && typeof handoff === "object" && "session" in handoff;
} Try / catch
try {
await beginOAuth(start, { host: "dialog" });
} catch (e) {
if (e instanceof Error && e.message.includes("preserve this sign-in")) {
showPopupBlockedHelp(); // instruct user to allow popups, offer same-tab retry
} else throw e;
} Prevention
- Detect popup blockers up front (window.open returns null) and warn before starting OAuth.
- Reopen the dialog if `popup.closed` becomes true mid-flow instead of failing.
- Assert the start response contains `handoff` for reauthentication targets in dev tests.
- Keep a reference to the popup and listen for its close event to reset flow state.
When it happens
Trigger: Calling the OAuth start flow when the provider requires reauthentication and: `oauthPopupRef.current` is null or closed (host === "dialog"), `window` unavailable, or `start.handoff` is undefined.
Common situations: Browser blocked the popup so the ref is null; user closed the dialog before this step; server returned a reauthentication target but omitted the handoff payload; popup closed by user between steps.
Related errors
- [adapter-ui-loader] Failed to load UI parser for "${adapterT
- Failed to seed CEO instructions:
- [paperclip] UI dist not found; running in API-only mode
- Select an organization to test adapter environment
- OAuth callback connection belongs to a missing company
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/b0028da557f5572f.
Report an issue: GitHub.