{"record":{"id":"a7f3393efb619b7c","repo":"mastra-ai/mastra","slug":"app-deletion-failed-data-error","errorCode":null,"errorMessage":"App deletion failed: ${data.error}","messagePattern":"App deletion failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"channels/slack/src/client.ts","lineNumber":186,"sourceCode":"    await this.rotateToken();\n\n    const response = await fetch(`${SLACK_API_BASE}/apps.manifest.delete`, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        Authorization: `Bearer ${this.#token}`,\n      },\n      body: JSON.stringify({ app_id: appId }),\n      signal: AbortSignal.timeout(SLACK_API_TIMEOUT_MS),\n    });\n\n    const data = (await response.json()) as {\n      ok: boolean;\n      error?: string;\n    };\n\n    if (!data.ok) {\n      throw new Error(`App deletion failed: ${data.error}`);\n    }\n  }\n\n  /**\n   * Check whether a Slack app still exists.\n   *\n   * Uses the read-only `apps.manifest.export` endpoint as an existence probe.\n   * Returns `false` when Slack reports the app is missing/inaccessible\n   * (e.g. it was deleted from the Slack admin UI), `true` when it exports\n   * successfully. Network/transport errors are re-thrown so callers can\n   * distinguish \"app is gone\" from \"couldn't reach Slack\".\n   */\n  async appExists(appId: string): Promise<boolean> {\n    await this.rotateToken();\n\n    const response = await fetch(`${SLACK_API_BASE}/apps.manifest.export`, {\n      method: 'POST',\n      headers: {","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/channels/slack/src/client.ts#L168-L204","documentation":"deleteApp calls Slack's app-deletion endpoint and expects ok:true; any ok:false response is converted into this error carrying Slack's error string.","triggerScenarios":"deleteApp() (typically invoked during channel disconnect) receives { ok: false, error: <string> } from Slack — e.g. invalid app token, app already deleted, or Slack-side failure.","commonSituations":"Disconnecting a channel whose app was already deleted manually in Slack; expired/rotated app configuration token; transient Slack API outage during disconnect.","solutions":["Check the Slack error in the message; if the app was already deleted, treat disconnect as complete and clear local state","Refresh your app configuration tokens from https://api.slack.com/apps and retry","Retry on transient errors; if persistent, verify the appId and token used for deletion are correct"],"exampleFix":"// before\nawait slackClient.deleteApp(appId); // throws if already deleted\n// after\ntry { await slackClient.deleteApp(appId); } catch (e) {\n  if (String(e).includes('already_deleted')) return; // idempotent disconnect\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await client.deleteApp(appId);\n} catch (e) {\n  const msg = (e as Error).message;\n  if (msg.startsWith('App deletion failed:')) {\n    if (/already/i.test(msg)) return; // treat as idempotent success\n    await backoffRetry(() => client.deleteApp(appId));\n  } else throw e;\n}","preventionTips":["Make disconnect flows idempotent — apps may already be deleted","Retry transient failures with backoff","Keep app configuration tokens fresh","Log the Slack error string for diagnosis"],"tags":["slack","api","lifecycle"],"backgroundTag":"slack-app-api-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}