{"record":{"id":"f497ea6c5f296e1c","repo":"mastra-ai/mastra","slug":"token-rotation-returned-incomplete-data","errorCode":null,"errorMessage":"Token rotation returned incomplete data","messagePattern":"Token rotation returned incomplete data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"channels/slack/src/client.ts","lineNumber":94,"sourceCode":"    const data = (await response.json()) as {\n      ok: boolean;\n      error?: string;\n      token?: string;\n      refresh_token?: string;\n    };\n\n    if (!data.ok) {\n      if (data.error === 'invalid_refresh_token') {\n        throw new Error(\n          'Slack refresh token is invalid. Get fresh tokens from https://api.slack.com/apps > \"Your App Configuration Tokens\". ' +\n            'This can happen if storage was lost or the token was already used.',\n        );\n      }\n      throw new Error(`Token rotation failed: ${data.error}`);\n    }\n\n    if (!data.token || !data.refresh_token) {\n      throw new Error('Token rotation returned incomplete data');\n    }\n\n    this.#token = data.token;\n    this.#refreshToken = data.refresh_token;\n\n    if (this.#onTokenRotation) {\n      await this.#onTokenRotation({\n        token: this.#token,\n        refreshToken: this.#refreshToken,\n      });\n    }\n  }\n\n  /**\n   * Create a new Slack app from a manifest.\n   */\n  async createApp(manifest: SlackAppManifest): Promise<SlackAppCredentials> {\n    // Ensure tokens are fresh","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/channels/slack/src/client.ts#L76-L112","documentation":"After a successful-looking rotation response (ok:true), the client expects both token and refresh_token fields. If either is missing the response is unusable — installing a partial token would break subsequent API calls — so it throws before mutating state.","triggerScenarios":"Slack's rotation endpoint returns ok:true but omits token or refresh_token from the JSON body during #doRotateToken/rotateToken().","commonSituations":"Slack API contract/behavior changes or partial outages; unexpected response shape due to API version drift; proxies or middleware stripping response fields.","solutions":["Log the raw rotation response to confirm the missing fields, then retry rotation","Check for Slack API changes/changelog and update @mastra/channels-slack to the latest version","Pin/verify no HTTP proxy or interceptor is mutating the response body"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isCompleteRotationResponse(d: unknown): d is { token: string; refresh_token: string } {\n  return typeof d === 'object' && d !== null && typeof (d as any).token === 'string' && typeof (d as any).refresh_token === 'string';\n}","tryCatchPattern":"try {\n  await client.rotateToken();\n} catch (e) {\n  if ((e as Error).message === 'Token rotation returned incomplete data') {\n    logger.error('slack rotation returned incomplete body; retrying');\n    await retry(() => client.rotateToken());\n  } else throw e;\n}","preventionTips":["Keep the package updated for Slack API contract changes","Log raw responses when rotation fails to aid debugging","Audit any proxies/middleware for response mutation"],"tags":["slack","token-rotation","api-contract"],"backgroundTag":"api-response-contract-mismatch","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}