{"record":{"id":"546935d84239af6f","repo":"thedotmack/claude-mem","slug":"telegram-api-responded-status-statustext","errorCode":null,"errorMessage":"Telegram API responded ${status} ${statusText}","messagePattern":"Telegram API responded (.+?) (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/services/integrations/TelegramNotifier.ts","lineNumber":63,"sourceCode":"  const idEscaped = escapeMarkdownV2(String(observationId));\n  return `${emoji} *${type}* — ${title}\\n${subtitle}\\nProject: \\`${projectEscaped}\\` · obs \\\\#${idEscaped}`;\n}\n\nasync function postOne(botToken: string, chatId: string, text: string): Promise<void> {\n  const url = `https://api.telegram.org/bot${botToken}/sendMessage`;\n  const response = await fetch(url, {\n    method: 'POST',\n    headers: { 'content-type': 'application/json' },\n    body: JSON.stringify({\n      chat_id: chatId,\n      text,\n      parse_mode: 'MarkdownV2',\n    }),\n  });\n  if (!response.ok) {\n    const status = response.status;\n    const statusText = response.statusText;\n    throw new Error(`Telegram API responded ${status} ${statusText}`);\n  }\n}\n\nexport async function notifyTelegram(input: TelegramNotifyInput): Promise<void> {\n  const settings = SettingsDefaultsManager.loadFromFile(USER_SETTINGS_PATH);\n\n  if (settings.CLAUDE_MEM_TELEGRAM_ENABLED !== 'true') {\n    return;\n  }\n\n  const botToken = settings.CLAUDE_MEM_TELEGRAM_BOT_TOKEN;\n  const chatId = settings.CLAUDE_MEM_TELEGRAM_CHAT_ID;\n  if (!botToken || !chatId) {\n    return;\n  }\n\n  const triggerTypes = splitCsv(settings.CLAUDE_MEM_TELEGRAM_TRIGGER_TYPES);\n  const triggerConcepts = splitCsv(settings.CLAUDE_MEM_TELEGRAM_TRIGGER_CONCEPTS);","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/src/services/integrations/TelegramNotifier.ts#L45-L81","documentation":"postOne() sends a single sendMessage request to the Telegram Bot API; if the response is not ok it throws an Error with the HTTP status and statusText. The caller notifyTelegram wraps each observation's send in its own try/catch and logs a warning, so one bad send does not abort the batch — but the message for that observation is lost.","triggerScenarios":"Telegram returns non-2xx for a sendMessage call: 401 unauthorized (bad bot token), 400 bad request (chat_id unknown, bot can't message the chat, MarkdownV2 parse error), 403 forbidden (chat blocked the bot), 429 rate limited.","commonSituations":"CLAUDE_MEM_TELEGRAM_BOT_TOKEN is wrong or revoked; CLAUDE_MEM_TELEGRAM_CHAT_ID is wrong or the user never started /start with the bot; message text contains unescaped MarkdownV2 special chars (the formatter escapes most, but user content can still trip it); hitting Telegram rate limits during a burst of observations.","solutions":["Verify the bot token: curl https://api.telegram.org/bot<TOKEN>/getMe — a 401 means the token is wrong/revoked.","Confirm chat_id by sending /start to the bot and checking getUpdates; ensure the chat_id in settings matches.","If MarkdownV2 parsing fails, simplify the message or switch parse_mode; ensure escapeMarkdownV2 is applied to all dynamic text.","For 429, reduce notification volume or add backoff between sends."],"exampleFix":"# before\ncurl https://api.telegram.org/bot$TOKEN/sendMessage -d chat_id=$CHAT -d text=hi\n# -> {\"ok\":false,\"error_code\":401,\"description\":\"Unauthorized\"}\n\n# after — regenerate token via @BotFather, set it\nexport CLAUDE_MEM_TELEGRAM_BOT_TOKEN='<new-token>'","handlingStrategy":"try-catch","validationCode":"// Validate token/chatId shape before sending.\nfunction telegramConfigValid(token?: string, chatId?: string): boolean {\n  return /^\\d+:\\w{30,}$/.test(token ?? '') && /^-?\\d+$/.test(chatId ?? '');\n}","typeGuard":"function isTelegramApiError(e: unknown): boolean {\n  return e instanceof Error && /Telegram API responded \\d+/.test(e.message);\n}","tryCatchPattern":"// notifyTelegram already wraps each send; mirror that pattern when calling directly.\ntry {\n  await postOne(botToken, chatId, text);\n} catch (e) {\n  if (e instanceof Error && /Telegram API responded/.test(e.message)) {\n    logger.warn('TELEGRAM', 'Telegram send failed; non-fatal', {}, e);\n    return; // one failed message must not break the batch\n  }\n  throw e;\n}","preventionTips":["Verify the bot token with getMe during configuration.","Have the target chat /start the bot so the chat_id is valid and reachable.","Treat notification failures as non-fatal (the existing loop already logs-and-continues).","Escape all dynamic text for MarkdownV2 parse_mode."],"tags":["telegram","notifications","http","config","external-api"],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}