calcom/cal.diy · error · Error
app_ticket invalid, please try again
Error message
app_ticket invalid, please try again
What it means
Thrown by getAppAccessToken when Feishu returns code 10012 on the app_access_token request, indicating the supplied app_ticket is invalid (typically outdated). The handler first clears the stored app_ticket in the DB (so the next call will fetch a fresh one) and then throws so the caller retries.
Source
Thrown at packages/app-store/feishucalendar/lib/AppAccessToken.ts:140
body: JSON.stringify({
app_id: appKeys.app_id,
app_secret: appKeys.app_secret,
app_ticket,
}),
});
const resp = await fetchAppAccessToken(appTicket);
const data = await resp.json();
if (!resp.ok || data.code !== 0) {
logger.error("feishu error with error: ", data, ", logid is:", resp.headers.get("X-Tt-Logid"));
// appticket invalid, mostly outdated, delete and renew one
if (data.code === 10012) {
await prisma.app.update({
where: { slug: "feishu-calendar" },
data: { keys: { ...appKeys, app_ticket: "" } },
});
throw new Error("app_ticket invalid, please try again");
}
}
const newAppAccessToken = data.app_access_token;
const newExpireDate = Math.round(Number(new Date()) / 1000 + data.expire);
await prisma.app.update({
where: { slug: "feishu-calendar" },
data: {
keys: {
...appKeys,
app_access_token: newAppAccessToken,
expire_date: newExpireDate,
},
},
});
return newAppAccessToken;View on GitHub (pinned to 176037d0af)
Solutions
- Retry the operation: the handler already cleared the bad ticket, so the next getAppAccessToken triggers getAppTicket which requests a fresh one from Feishu.
- Ensure the app_ticket webhook is functional (see error 552) so a new ticket is delivered.
- Verify app_id and app_secret in the Feishu app keys are correct.
- Wrap getAppAccessToken callers in a single-retry loop keyed on this error message.
Example fix
// before - single call, throws on 10012
const token = await getAppAccessToken();
// after - one automatic retry after ticket reset
async function getAppAccessTokenWithRetry() {
try {
return await getAppAccessToken();
} catch (err) {
if (err instanceof Error && err.message.includes("app_ticket invalid")) {
return await getAppAccessToken();
}
throw err;
}
} Defensive patterns
Strategy: retry
Validate before calling
// ensure stored ticket is fresh before requesting access token
const keys = await getAppKeys();
if (keys.app_ticket && Date.now() - (keys.app_ticket_received_at ?? 0) > 60 * 60 * 1000) {
await prisma.app.update({ where: { slug: "feishu-calendar" }, data: { keys: { ...keys, app_ticket: "" } } });
} Type guard
const isAppAccessTokenResp = (v: any): boolean => typeof v?.code === "number";
Try / catch
async function getAppAccessTokenWithRetry() {
try { return await getAppAccessToken(); }
catch (err) {
if (err instanceof Error && /app_ticket invalid/i.test(err.message)) return await getAppAccessToken();
throw err;
}
} Prevention
- Wrap getAppAccessToken in a single-retry loop to absorb a stale-ticket 10012.
- Keep the app_ticket webhook healthy (see error 552).
- Verify app_id/app_secret match the Feishu app that issued the ticket.
When it happens
Trigger: Feishu POST /open-apis/auth/v3/app_access_token returns code === 10012 because the app_ticket stored in DB is stale, expired (Feishu tickets live ~1 hour), or was issued for a different app_id.
Common situations: Stale app_ticket persisted from a previous app configuration; clock skew; Feishu rotated tickets but the webhook that updates DB failed; app_id/app_secret mismatch between Cal.com keys and the Feishu app.
Related errors
- No app ticket found
- Feishu Calendar refresh token expired
- get access token error
- no calendar id
- no calendar id provided in createAttendees
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/1841822c8d121e26.
Report an issue: GitHub.