different-ai/openwork · error

Failed to sign in to OpenWork Cloud.

Error message

Failed to sign in to OpenWork Cloud.

What it means

exchangeHandoffAndSignIn exchanges a one-time desktop handoff grant for a Den session. After the exchange succeeds, it requires the result to contain a session token; if exchange.token is falsy it throws the fallback Error "Failed to sign in to OpenWork Cloud.". This is the generic sign-in failure surfaced when no more specific error message was provided or produced.

Source

Thrown at apps/app/src/app/lib/den-handoff.ts:80

  grant: string,
  options: ExchangeHandoffOptions,
): Promise<ExchangeHandoffResult> {
  const fallback = options.fallbackErrorMessage ?? "Failed to sign in to OpenWork Cloud.";
  const storedSettings = readDenSettings();
  const apiBaseUrl = options.apiBaseUrl ?? (
    storedSettings.baseUrl === resolveDenBaseUrls(options.baseUrl).baseUrl
      ? storedSettings.apiBaseUrl
      : undefined
  );
  const client = options.client ?? createDenClient({
    baseUrl: options.baseUrl,
    apiBaseUrl,
  });

  try {
    const exchange = await client.exchangeDesktopHandoff(grant);
    if (!exchange.token) {
      throw new Error(fallback);
    }

    if (typeof window !== "undefined") {
      try {
        window.sessionStorage.setItem(DEN_HANDOFF_AUTO_CONTINUE_KEY, String(Date.now()));
      } catch {}
    }
    const desktopInitiated = options.desktopInitiated ?? hasActiveDesktopSignInIntent();
    clearDesktopSignInIntent();
    const plan = resolveHandoffOrgPlan({
      explicitActiveOrg: options.activeOrg ?? null,
      exchangeOrganization: exchange.organization ?? null,
      desktopInitiated,
    });
    if (plan.kind === "await-user-selection") {
      // Desktop-initiated sign-in: hold the org choice for the onboarding
      // step. The exchange-reported org is only the chooser's default;
      // single-org accounts still auto-select there without a visible stop.

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Verify the handoff grant is fresh and single-use; restart the sign-in flow to mint a new grant
  2. Check the Den server is healthy and returns a token in the desktop-handoff exchange response
  3. Provide options.fallbackErrorMessage for a more specific message and inspect the original cause in logs
  4. Retry the whole handoff (deep link or paste) from the browser flow

Example fix

// before
const result = await exchangeHandoffAndSignIn(consumedGrant, { baseUrl });
// after
const result = await exchangeHandoffAndSignIn(consumedGrant, { baseUrl, fallbackErrorMessage: `Cloud sign-in failed (grant ${consumedGrant.slice(0, 6)}…)` });
if (!result.ok) console.error(result.error);
Defensive patterns

Strategy: try-catch

Validate before calling

if (typeof grant !== "string" || grant.length === 0) throw new Error("A handoff grant is required before sign-in");

Type guard

const hasSessionToken = (x: DenDesktopHandoffExchange): x is DenDesktopHandoffExchange & { token: string } =>
  typeof x.token === "string" && x.token.length > 0;

Try / catch

const result = await exchangeHandoffAndSignIn(grant, { baseUrl });
if (!result.ok) {
  console.error("Cloud sign-in failed:", result.error);
  showSignInRetryDialog(result.error);
}

Prevention

When it happens

Trigger: client.exchangeDesktopHandoff(grant) resolves successfully but the returned DenDesktopHandoffExchange has no token — e.g. the server accepted the request but did not issue a session.

Common situations: A stale or already-consumed handoff grant that the server resolves without a token, a misconfigured Den server returning an unexpected payload shape, or testing with a mock client that omits token.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/964fe5e97430e965. Report an issue: GitHub.