dubinc/dub · error

Access token not found for the account.

Error message

Access token not found for the account.

What it means

getValidToken loads the stored Dub token from Stripe app secrets (name "dub_token"); when no secret exists it throws this message. It means the account never completed (or its data was lost from) the Dub connect flow, so no token is available to validate or refresh.

Source

Thrown at packages/stripe-app/src/utils/oauth.ts:98

    throw new Error("Failed to fetch user info from Dub.", {
      cause: data.error,
    });
  }

  const { workspace } = data as { workspace: Workspace };

  return workspace;
}

// If the token is expired, it will refresh it
export async function getValidToken({ stripe }: { stripe: Stripe }) {
  const token = await getSecret<Token>({
    stripe,
    name: "dub_token",
  });

  if (!token) {
    throw new Error("Access token not found for the account.");
  }

  try {
    await getUserInfo({ token });
  } catch (e) {
    const refreshedToken = await refreshToken({ token });

    if (!refreshedToken) {
      console.error("Failed to refresh access token.");
      return null;
    }

    await setSecret({
      stripe,
      name: "dub_token",
      payload: JSON.stringify(refreshedToken),
    });

View on GitHub (pinned to f216b94a24)

Solutions

  1. Complete the Dub connect/OAuth flow in the Stripe App so dub_token is stored as a secret.
  2. Verify you are operating on the same Stripe account that performed the connection.
  3. Reinstall/re-authorize the Stripe App if secrets were wiped.
  4. Add a UX guard: check for the token first and show 'Connect Dub' instead of a raw error.

Example fix

// before
const token = await getValidToken(stripe); // throws for unconnected accounts
// after
const stored = await getSecret({ stripe, name: "dub_token" });
if (!stored) return showConnectOnboarding();
Defensive patterns

Strategy: validation

Validate before calling

const stored = await getSecret<Token>({ stripe, name: "dub_token" });
if (!stored) {
  // render onboarding instead of calling Dub-dependent handlers
  return respondWith({ connectUrl: buildDubConnectUrl(stripeAccountId) });
}

Type guard

function isStoredToken(v: unknown): v is { access_token: string; refresh_token: string } {
  return typeof v === "object" && v !== null && typeof (v as any).access_token === "string" && typeof (v as any).refresh_token === "string";
}

Try / catch

try {
  const token = await getValidToken({ stripe });
} catch (e) {
  if ((e as Error).message === "Access token not found for the account.") {
    return startDubOnboarding(stripeAccountId); // friendly connect flow
  }
  throw e;
}

Prevention

When it happens

Trigger: A Stripe App request path calls getValidToken (via the `token` handler) for an account where getSecret returns null — the user installed the app but never authorized Dub, or the secret was deleted.

Common situations: Stripe App installed but OAuth connect step skipped; secrets cleared by reinstall; calling Dub-backed features from a different Stripe account than the one that connected.

Related errors


AI-assisted analysis of dubinc/dub@f216b94a24 (2026-08-31). Data as JSON: /api/errors/245991eecc07af93. Report an issue: GitHub.