{"record":{"id":"1b1a13780e115ac2","repo":"calcom/cal.diy","slug":"no-app-ticket-found","errorCode":null,"errorMessage":"No app ticket found","messagePattern":"No app ticket found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/app-store/feishucalendar/lib/AppAccessToken.ts","lineNumber":100,"sourceCode":"\n  /**\n   * 1. App_ticket is only valid for 1 hr.\n   * 2. The we cannot retrieve app_ticket by calling a API.\n   * 3. App_ticket can only be retrieved in app_ticket event, which is push from feishu every hour.\n   * 4. We can trigger feishu to push a new app_ticket\n   * 5. Therefore, after trigger resend app_ticket ticket, we have to\n   * pooling DB, as app_ticket will update ticket in DB\n   * see\n   * https://open.larksuite.com/document/ugTN1YjL4UTN24CO1UjN/uQjN1YjL0YTN24CN2UjN\n   * https://open.larksuite.com/document/ukTMukTMukTM/ukDNz4SO0MjL5QzM/auth-v3/auth/app_ticket_resend\n   */\n  const appTicketNew = await makePoolingPromise(getAppTicketFromKeys);\n  if (appTicketNew) {\n    log.debug(\"has new app ticket\", appTicketNew);\n    return appTicketNew;\n  }\n  log.error(\"app ticket not found\");\n  throw new Error(\"No app ticket found\");\n};\n\nexport const getAppAccessToken: () => Promise<string> = async () => {\n  log.debug(\"get app access token invoked\");\n  const appKeys = await getValidAppKeys();\n  const appAccessToken = appKeys.app_access_token;\n  const expireDate = appKeys.expire_date;\n\n  if (appAccessToken && expireDate && !isExpired(expireDate)) {\n    log.debug(\"get app access token not expired\");\n    return appAccessToken;\n  }\n\n  const appTicket = await getAppTicket();\n\n  const fetchAppAccessToken = (app_ticket: string) =>\n    fetch(`https://${FEISHU_HOST}/open-apis/auth/v3/app_access_token`, {\n      method: \"POST\",","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/packages/app-store/feishucalendar/lib/AppAccessToken.ts#L82-L118","documentation":"Thrown by getAppTicket in the Feishu calendar adapter when the app_ticket cannot be obtained. Feishu only delivers app_ticket via an event webhook (not a direct fetch); the handler triggers a resend and then pools the database (makePoolingPromise, 24 retries × 5s ≈ 2 minutes). If no ticket arrives within the window, it throws.","triggerScenarios":"Feishu webhook endpoint for app_ticket events is not reachable (public URL not configured), the webhook was not registered for the Feishu app, the app's event subscription is disabled, or 2 minutes elapsed without Feishu pushing a new ticket.","commonSituations":"Self-hosted Cal.com without a public webhook URL; Feishu app's 'event subscription' missing the app_ticket event; Feishu app in review mode with webhooks disabled; network firewall blocking inbound Feishu webhook POST.","solutions":["Expose a public HTTPS URL for the Feishu webhook endpoint and register it in the Feishu developer console under event subscriptions.","Enable the app_ticket event in the Feishu app's event configuration.","Verify the Cal.com app's app_id / app_secret match the Feishu app so Feishu will push the ticket.","Trigger the resend manually from the Feishu console to seed the DB, then retry.","Increase the pooling window (times/delay in makePoolingPromise) if Feishu webhooks are slow."],"exampleFix":"// before\nconst appTicketNew = await makePoolingPromise(getAppTicketFromKeys);\nif (appTicketNew) return appTicketNew;\nlog.error(\"app ticket not found\");\nthrow new Error(\"No app ticket found\");\n\n// after - extend window and surface cause\nconst appTicketNew = await makePoolingPromise(getAppTicketFromKeys, 60, 5_000);\nif (!appTicketNew) {\n  throw new Error(\"No Feishu app_ticket received within 5 minutes. Verify the app_ticket webhook is publicly reachable and the event is subscribed.\");\n}\nreturn appTicketNew;","handlingStrategy":"retry","validationCode":"const appKeys = await getAppKeys();\nif (!appKeys?.app_id || !appKeys?.app_secret) throw new Error(\"Feishu app_id/app_secret not configured\");\nif (!appKeys?.open_verification_token) throw new Error(\"Feishu open_verification_token not configured\");","typeGuard":"const hasFeishuAppKeys = (k: unknown): k is { app_id: string; app_secret: string } =>\n  typeof k === \"object\" && k !== null &&\n  typeof (k as any).app_id === \"string\" && typeof (k as any).app_secret === \"string\";","tryCatchPattern":"try {\n  const token = await getAppAccessToken();\n} catch (err) {\n  if (err instanceof Error && /No app ticket found/i.test(err.message)) {\n    // surface actionable guidance to ops\n    throw new Error(\"Feishu app_ticket webhook unreachable. Register the app_ticket event subscription and expose a public callback URL.\");\n  }\n  throw err;\n}","preventionTips":["Register the app_ticket event subscription in the Feishu developer console.","Expose a public HTTPS webhook URL and verify it receives Feishu POSTs.","Run a synthetic that triggers a ticket resend daily so a fresh ticket is always in DB."],"tags":["feishu","larksuite","app-ticket","webhook","oauth","retry"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}