calcom/cal.diy · error · Error
Unhandled appSlug: ${appSlug}
Error message
Unhandled appSlug: ${appSlug} What it means
Thrown by the example credential-sync setTokenInCalCom endpoint when req.query.appSlug is neither 'google-calendar' nor 'zoom'. Unlike getToken, this reads appSlug from query params and pushes a token into Cal.com via the credential-sync admin API. The error message interpolates the offending slug for easier debugging.
Source
Thrown at example-apps/credential-sync/pages/api/setTokenInCalCom.ts:25
CALCOM_CREDENTIAL_SYNC_SECRET,
CALCOM_CREDENTIAL_SYNC_HEADER_NAME,
CALCOM_ADMIN_API_KEY,
} from "../../constants";
import { generateGoogleCalendarAccessToken, generateZoomAccessToken } from "../../lib/integrations";
export default async function handler(req: NextApiRequest, res) {
const isInvalid = req.query.invalid === "1";
const userId = parseInt(req.query.userId as string, 10);
const appSlug = req.query.appSlug;
try {
let accessToken;
if (appSlug === "google-calendar") {
accessToken = await generateGoogleCalendarAccessToken();
} else if (appSlug === "zoom") {
accessToken = await generateZoomAccessToken();
} else {
throw new Error(`Unhandled appSlug: ${appSlug}`);
}
if (!accessToken) {
return res.status(500).json({ error: "Could not get access token" });
}
const result = await fetch(
`http://localhost:3002/api/v1/credential-sync?apiKey=${CALCOM_ADMIN_API_KEY}&userId=${userId}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
[CALCOM_CREDENTIAL_SYNC_HEADER_NAME]: CALCOM_CREDENTIAL_SYNC_SECRET,
},
body: JSON.stringify({
appSlug,
encryptedKey: symmetricEncrypt(
JSON.stringify({View on GitHub (pinned to 176037d0af)
Solutions
- Add a branch (or a lookup table) for the new appSlug and its token generator.
- Ensure the request includes appSlug as a query parameter with an exact supported value.
- Validate appSlug at the top and return a clear 400 listing supported slugs.
Example fix
// before
if (appSlug === 'google-calendar') { ... }
else if (appSlug === 'zoom') { ... }
else { throw new Error(`Unhandled appSlug: ${appSlug}`); }
// after - validate early with a helpful message
const supported = ['google-calendar', 'zoom'];
if (!supported.includes(appSlug)) {
return res.status(400).json({ error: `Unsupported appSlug '${appSlug}'. Supported: ${supported.join(', ')}` });
} Defensive patterns
Strategy: validation
Validate before calling
const supported = ['google-calendar', 'zoom'];
if (!supported.includes(appSlug as string)) {
return res.status(400).json({ error: `Unsupported appSlug '${appSlug}'. Supported: ${supported.join(', ')}` });
} Type guard
function isSupportedSlug(s: unknown): s is 'google-calendar' | 'zoom' {
return s === 'google-calendar' || s === 'zoom';
} Try / catch
null
Prevention
- Validate appSlug query param against an allowlist at the top of the handler.
- Extend the allowlist and branches together when adding providers.
- Return supported values in the error to guide the caller.
When it happens
Trigger: GET /api/setTokenInCalCom?appSlug=<other>&userId=... where appSlug is not one of the two supported values, or is missing entirely (undefined).
Common situations: Adding a third provider without extending setTokenInCalCom; the query string missing appSlug; a typo like 'gcal' instead of 'google-calendar'; automated test hitting the endpoint with an unsupported slug.
Related errors
- Unhandled values
- Unable to generate token
- Invalid refreshed tokens were returned
- `code` must be a string
- ApiKeysService -Cannot set both apiKeyDaysValid and apiKeyNe
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/a30224cfd9f7baec.
Report an issue: GitHub.