{"record":{"id":"d3658f949a25f16b","repo":"mastra-ai/mastra","slug":"telegram-method-failed-detail","errorCode":null,"errorMessage":"Telegram ${method} failed: ${detail}","messagePattern":"Telegram (.+?) failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"channels/telegram/src/telegram-client.ts","lineNumber":50,"sourceCode":"      ? undefined\n      : { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload) };\n  let response: Response;\n  try {\n    response = await fetch(`${apiBaseUrl}/bot${botToken}/${method}`, {\n      ...init,\n      signal: AbortSignal.timeout(10_000),\n    });\n  } catch (cause) {\n    // Tag transport/timeout failures so callers can tell them apart from an\n    // `ok: false` API response (see getMe).\n    throw Object.assign(new Error(`Telegram ${method} request failed`, { cause }), {\n      isTransportError: true,\n    });\n  }\n  const body = (await response.json().catch(() => null)) as TelegramApiResponse<TResult> | null;\n  if (!response.ok || !body?.ok) {\n    const detail = body?.description ?? `HTTP ${response.status}`;\n    throw new Error(`Telegram ${method} failed: ${detail}`);\n  }\n  return body.result as TResult;\n}\n\n/**\n * Validate a bot token via `getMe` and resolve the bot's identity. Throws if\n * the token is rejected or the returned user is not a bot.\n *\n * @see https://core.telegram.org/bots/api#getme\n */\nexport async function getMe(botToken: string, apiBaseUrl: string = TELEGRAM_API_BASE_URL): Promise<TelegramUser> {\n  let result: TelegramUser;\n  try {\n    result = await botApiRequest<TelegramUser>(botToken, 'getMe', apiBaseUrl);\n  } catch (cause) {\n    // A transport/timeout failure is a connectivity problem, not a token\n    // rejection — surface it as-is rather than mislabeling it as a bad token.\n    if (cause instanceof Error && (cause as { isTransportError?: boolean }).isTransportError) {","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/channels/telegram/src/telegram-client.ts#L32-L68","documentation":"botApiRequest is the low-level wrapper for all Telegram Bot API calls. It throws this error when the HTTP response is not ok or the JSON body has ok:false, using body.description (Telegram's human-readable error) or 'HTTP <status>' as detail. The thrown message embeds the method name (e.g. getMe, sendMessage) plus the detail, and transport errors (timeout/network) are thrown separately with isTransportError set.","triggerScenarios":"Any Telegram Bot API call where Slack—rather Telegram returns a non-2xx status or { ok: false, description: ... }: invalid bot token (401 Unauthorized), chat not found (400), rate limit (429), or Telegram 5xx.","commonSituations":"Storing/entering a revoked or typo'd bot token; sending messages to a chat the bot isn't a member of; hitting rate limits during bulk sends; Telegram API incidents.","solutions":["Read the detail in the message (e.g. 'Unauthorized', 'chat not found') and fix the corresponding input — most commonly validate the bot token with getMe.","If the token is invalid, regenerate it via @BotFather and update the stored installation.","Respect Telegram rate limits — back off and retry on 429 using retry_after.","For 5xx, retry with backoff; check https://telegram.org/status for outages."],"exampleFix":"// before\nawait client.sendMessage({ chat_id, text }); // throws on 'chat not found'\n// after\ntry {\n  await client.sendMessage({ chat_id, text });\n} catch (e) {\n  if (String(e.message).includes('429')) await sleep(retryAfter);\n  else if (String(e.message).includes('Unauthorized')) await revalidateToken();\n  else throw e;\n}","handlingStrategy":"retry","validationCode":"const me = await getMe(botToken); // validate token before other calls; throws 'rejected the bot token' if bad\nif (!me.is_bot) throw new Error('Not a bot token');","typeGuard":null,"tryCatchPattern":"try {\n  await client.sendMessage({ chat_id, text });\n} catch (e) {\n  const msg = e instanceof Error ? e.message : String(e);\n  if (msg.includes('429') || msg.includes('Too Many Requests')) {\n    await sleep(backoff); return retry();\n  }\n  if (msg.includes('5')) throw e; // 5xx: retry later\n  throw e; // 4xx: fix input (chat_id, token, permissions)\n}","preventionTips":["Validate tokens with getMe once at startup and cache the bot identity.","Implement per-chat rate limiting and honor Telegram retry_after on 429.","Check bot membership in target chats before sending."],"tags":["telegram","api","network","rate-limit"],"backgroundTag":"telegram-api-error","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}