calcom/cal.diy · error · Error
Unable to generate token
Error message
Unable to generate token
What it means
Thrown by the example credential-sync getToken endpoint when the chosen token-generation function (generateGoogleCalendarAccessToken or generateZoomAccessToken) returned a falsy value. This indicates the provider-specific generation logic ran but produced no usable token. Caught and returned as a 500 response.
Source
Thrown at example-apps/credential-sync/pages/api/getToken.ts:32
return res.status(403).json({ message: "Invalid secret" });
}
const calcomUserId = req.body.calcomUserId;
const appSlug = req.body.appSlug;
console.log("getToken Params", {
calcomUserId,
appSlug,
});
let accessToken;
if (appSlug === "google-calendar") {
accessToken = await generateGoogleCalendarAccessToken();
} else if (appSlug === "zoom") {
accessToken = await generateZoomAccessToken();
} else {
throw new Error("Unhandled values");
}
if (!accessToken) {
throw new Error("Unable to generate token");
}
res.status(200).json({
_1: true,
access_token: accessToken,
});
} catch (e) {
res.status(500).json({ error: e.message });
}
}
View on GitHub (pinned to 176037d0af)
Solutions
- Set the provider credentials required by lib/integrations (e.g. Google service account, Zoom client secret/refresh token) in the example app environment.
- Add logging inside the generator to see why it returned empty (provider error, expired refresh token).
- Re-authorize the provider to obtain a fresh refresh token.
- Return a non-empty token from the generator or throw a descriptive error instead of returning undefined.
Example fix
// before - generator returns undefined silently
export async function generateZoomAccessToken() {
const r = await fetch(...);
return r.ok ? (await r.json()).access_token : undefined;
}
// after - throw with reason so getToken can surface it
export async function generateZoomAccessToken() {
const r = await fetch(...);
if (!r.ok) throw new Error(`Zoom token HTTP ${r.status}`);
return (await r.json()).access_token;
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!accessToken) {
// surface a clear reason instead of a generic throw
return res.status(502).json({ error: `Token generation returned empty for ${appSlug}` });
} Type guard
function isNonEmptyToken(t: unknown): t is string {
return typeof t === 'string' && t.length > 0;
} Try / catch
try {
accessToken = appSlug === 'google-calendar' ? await generateGoogleCalendarAccessToken() : await generateZoomAccessToken();
} catch (genError) {
return res.status(502).json({ error: `Generator failed: ${genError.message}` });
}
if (!accessToken) return res.status(502).json({ error: 'Empty token from provider' }); Prevention
- Have generators throw a descriptive error instead of returning undefined.
- Set and verify provider credentials (Google service account, Zoom secrets) in the example app env.
- Log provider HTTP responses inside generators to diagnose empty tokens.
When it happens
Trigger: POST /api/getToken with a supported appSlug, but the underlying generator returned null/undefined/empty string. Typically because the example app's service-account credentials, refresh tokens, or OAuth client secrets are missing or invalid inside lib/integrations.
Common situations: Example app env vars (Google service account JSON, Zoom OAuth secrets) not set; refresh token expired or revoked; the generator silently returns undefined on a caught internal error; clock skew or quota limits causing the provider to return an empty token.
Related errors
- Unhandled values
- Could not refresh the token due to connection issue with the
- Invalid refreshed tokens were returned
- Unhandled appSlug: ${appSlug}
- Teams are not supported
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/a6483ed28bb8457e.
Report an issue: GitHub.