paperclipai/paperclip · error · OAuthHandoffError
unavailable
unavailable
Error message
Paperclip Cloud couldn’t prepare secure sign-in. Try again.
What it means
postCloudHandoff retries its POST to the Paperclip Cloud handoff endpoint; if every attempt fails at the network level (fetch threw) and no response was ever obtained, it throws OAuthHandoffError with code "unavailable". The message falls back to the last underlying error message when available, otherwise this generic guidance string.
Source
Thrown at ui/src/lib/oauthHandoff.ts:86
let lastError: unknown;
for (let attempt = 0; attempt < 2; attempt += 1) {
try {
response = await request(CLOUD_HANDOFF_PATH, {
method: "POST",
headers: { "content-type": "application/json", accept: "application/json" },
credentials: "include",
body: JSON.stringify({ session }),
signal: options.signal,
});
if (response.status < 500 || attempt === 1) return response;
} catch (error) {
if (options.signal?.aborted || (error instanceof DOMException && error.name === "AbortError")) throw error;
lastError = error;
if (attempt === 1) break;
}
}
if (response) return response;
throw new OAuthHandoffError(
lastError instanceof Error ? lastError.message : "Paperclip Cloud couldn’t prepare secure sign-in. Try again.",
"unavailable",
);
}
function exactReauthenticationTarget(value: unknown, session: string): PreparedOAuthNavigation | null {
if (typeof value !== "string" || typeof window === "undefined") return null;
try {
const url = new URL(value, window.location.origin);
if (
url.origin !== window.location.origin
|| url.pathname !== CLOUD_REAUTH_PATH
|| url.username
|| url.password
|| url.hash
|| url.searchParams.size !== 1
|| url.searchParams.get("session") !== session
) return null;View on GitHub (pinned to 01ad858492)
Solutions
- Check network connectivity and reachability of the Paperclip Cloud endpoint, then retry sign-in.
- Disable browser extensions/ad-blockers that may block the request and retry.
- Inspect the underlying `lastError` (the OAuthHandoffError message carries it) for the real cause.
- If it persists, verify the cloud handoff service status/endpoint configuration.
Example fix
// before
await prepareOAuthNavigation(start); // raw throw surfaces to user
// after
try {
await prepareOAuthNavigation(start);
} catch (e) {
if (e instanceof OAuthHandoffError && e.code === "unavailable") {
showRetryBanner("Network unavailable — retry sign-in");
} else throw e;
} Defensive patterns
Strategy: retry
Validate before calling
if (typeof navigator !== "undefined" && !navigator.onLine) {
showOfflineBanner(); return; // skip the request entirely
} Try / catch
try {
await prepareOAuthNavigation(start, { signal });
} catch (e) {
if (e instanceof OAuthHandoffError && e.code === "unavailable") {
scheduleRetryWithBackoff(() => prepareOAuthNavigation(start, { signal }));
} else throw e;
} Prevention
- Check navigator.onLine and gate sign-in on connectivity.
- Retry transient network failures with exponential backoff before surfacing the error.
- Monitor the cloud handoff endpoint's availability; alert on rising failure rates.
- Preserve the underlying lastError message for diagnostics rather than showing only the generic text.
When it happens
Trigger: Both fetch attempts to the cloud handoff endpoint threw (network down, DNS failure, CORS block, request aborted by something other than the caller's signal), leaving `response` null.
Common situations: User offline or on a captive portal; Paperclip Cloud endpoint unreachable; ad-blocker/extension blocking the request; mixed-content or CORS misconfiguration in a dev environment.
Related errors
- connector_refresh_failed
- No Tailscale address was detected during setup. The saved co
- No Tailscale address was detected during setup. The saved co
- Anthropic Managed Agents request failed with HTTP ${response
- Unable to inspect protocol eval history object: ${detail.sli
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/5891fcccbb5379b4.
Report an issue: GitHub.