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

  1. Check network connectivity and reachability of the Paperclip Cloud endpoint, then retry sign-in.
  2. Disable browser extensions/ad-blockers that may block the request and retry.
  3. Inspect the underlying `lastError` (the OAuthHandoffError message carries it) for the real cause.
  4. 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

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


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/5891fcccbb5379b4. Report an issue: GitHub.