{"record":{"id":"1841822c8d121e26","repo":"calcom/cal.diy","slug":"app-ticket-invalid-please-try-again","errorCode":null,"errorMessage":"app_ticket invalid, please try again","messagePattern":"app_ticket invalid, please try again","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/app-store/feishucalendar/lib/AppAccessToken.ts","lineNumber":140,"sourceCode":"      body: JSON.stringify({\n        app_id: appKeys.app_id,\n        app_secret: appKeys.app_secret,\n        app_ticket,\n      }),\n    });\n\n  const resp = await fetchAppAccessToken(appTicket);\n  const data = await resp.json();\n\n  if (!resp.ok || data.code !== 0) {\n    logger.error(\"feishu error with error: \", data, \", logid is:\", resp.headers.get(\"X-Tt-Logid\"));\n    // appticket invalid, mostly outdated, delete and renew one\n    if (data.code === 10012) {\n      await prisma.app.update({\n        where: { slug: \"feishu-calendar\" },\n        data: { keys: { ...appKeys, app_ticket: \"\" } },\n      });\n      throw new Error(\"app_ticket invalid, please try again\");\n    }\n  }\n\n  const newAppAccessToken = data.app_access_token;\n  const newExpireDate = Math.round(Number(new Date()) / 1000 + data.expire);\n\n  await prisma.app.update({\n    where: { slug: \"feishu-calendar\" },\n    data: {\n      keys: {\n        ...appKeys,\n        app_access_token: newAppAccessToken,\n        expire_date: newExpireDate,\n      },\n    },\n  });\n\n  return newAppAccessToken;","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/packages/app-store/feishucalendar/lib/AppAccessToken.ts#L122-L158","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before - single call, throws on 10012\nconst token = await getAppAccessToken();\n\n// after - one automatic retry after ticket reset\nasync function getAppAccessTokenWithRetry() {\n  try {\n    return await getAppAccessToken();\n  } catch (err) {\n    if (err instanceof Error && err.message.includes(\"app_ticket invalid\")) {\n      return await getAppAccessToken();\n    }\n    throw err;\n  }\n}","handlingStrategy":"retry","validationCode":"// ensure stored ticket is fresh before requesting access token\nconst keys = await getAppKeys();\nif (keys.app_ticket && Date.now() - (keys.app_ticket_received_at ?? 0) > 60 * 60 * 1000) {\n  await prisma.app.update({ where: { slug: \"feishu-calendar\" }, data: { keys: { ...keys, app_ticket: \"\" } } });\n}","typeGuard":"const isAppAccessTokenResp = (v: any): boolean => typeof v?.code === \"number\";","tryCatchPattern":"async function getAppAccessTokenWithRetry() {\n  try { return await getAppAccessToken(); }\n  catch (err) {\n    if (err instanceof Error && /app_ticket invalid/i.test(err.message)) return await getAppAccessToken();\n    throw err;\n  }\n}","preventionTips":["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."],"tags":["feishu","larksuite","app-ticket","app-access-token","retry"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}