calcom/cal.diy · error · Error

Error refreshing dub token: ${res?.error?.message ?? respons

Error message

Error refreshing dub token: ${res?.error?.message ?? response.statusText}

What it means

Thrown inside Dub AnalyticsService.refreshAccessToken when Dub's token-refresh endpoint returns a non-2xx response. The handler reads the JSON body, marks the stored Cal.com credential invalid on HTTP 401 (so the user must re-authenticate), then throws an Error whose message interpolates Dub's error.message (or response.statusText as fallback).

Source

Thrown at packages/app-store/dub/lib/AnalyticsService.ts:87

              grant_type: "refresh_token",
              refresh_token: refreshToken,
            }).toString(),
            headers: {
              "Content-Type": "application/x-www-form-urlencoded",
            },
          });

          if (!response.ok) {
            const res = await response.json();
            if (response.status === 401) {
              await CredentialRepository.updateCredentialById({
                id: this.credential.id,
                data: {
                  invalid: true,
                },
              });
            }
            throw new Error(`Error refreshing dub token: ${res?.error?.message ?? response.statusText}`);
          }
          return await response.json();
        },
        "dub",
        this.credential.userId
      );

      newToken.expiry_date = Date.now() + newToken.expires_in * 1000;

      await CredentialRepository.updateCredentialById({
        id: this.credential.id,
        data: { key: newToken as any },
      });

      return newToken;
    } catch (err) {
      this.log.error(err);
      throw err;

View on GitHub (pinned to 176037d0af)

Solutions

  1. On 401, prompt the user to reinstall the Dub integration (the credential is already flagged invalid by the handler).
  2. Verify the Dub app's client_id and client_secret in /apps/dub keys are current.
  3. For 429/5xx, retry with exponential backoff before surfacing failure.
  4. Confirm refresh_token was the most recent one returned by Dub (using a stale token after a refresh produces this error).

Example fix

// before
throw new Error(`Error refreshing dub token: ${res?.error?.message ?? response.statusText}`);

// after - typed error so callers can branch
if (response.status === 401) {
  throw new DubTokenInvalidError(`Dub refresh failed: ${res?.error?.message ?? response.statusText}`, { credentialId: this.credential.id });
}
throw new Error(`Error refreshing dub token: ${res?.error?.message ?? response.statusText}`, { cause: res });
Defensive patterns

Strategy: try-catch

Validate before calling

if (!token?.refresh_token) throw new Error("No Dub refresh token stored; reinstall Dub integration.");

Type guard

const isDubToken = (t: unknown): t is { access_token: string; refresh_token: string; expires_in: number } =>
  typeof t === "object" && t !== null &&
  typeof (t as any).access_token === "string" &&
  typeof (t as any).refresh_token === "string";

Try / catch

try {
  await analyticsService.sendEvent(...);
} catch (err) {
  if (err instanceof Error && /refreshing dub token/i.test(err.message)) {
    // credential was flagged invalid on 401; prompt reinstall
    await notifyUserReconnectDub(credentialId);
    return; // analytics is non-critical
  }
  throw err;
}

Prevention

When it happens

Trigger: POST https://api.dub.co/oauth/token with grant_type=refresh_token returns non-2xx: refresh_token expired/revoked (401), client_secret wrong (401), rate limited (429), or Dub API outage (5xx).

Common situations: Dub refresh token older than 30 days (Dub tokens expire); user revoked Cal.com access in Dub; client_secret rotated but app keys not updated; Dub API rate limit; transient Dub 5xx.

Related errors


AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12). Data as JSON: /api/errors/a9a3f9975be67de6. Report an issue: GitHub.