thedotmack/claude-mem · warning · Error

Telegram API responded ${status} ${statusText}

Error message

Telegram API responded ${status} ${statusText}

What it means

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.

Source

Thrown at src/services/integrations/TelegramNotifier.ts:63

  const idEscaped = escapeMarkdownV2(String(observationId));
  return `${emoji} *${type}* — ${title}\n${subtitle}\nProject: \`${projectEscaped}\` · obs \\#${idEscaped}`;
}

async function postOne(botToken: string, chatId: string, text: string): Promise<void> {
  const url = `https://api.telegram.org/bot${botToken}/sendMessage`;
  const response = await fetch(url, {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify({
      chat_id: chatId,
      text,
      parse_mode: 'MarkdownV2',
    }),
  });
  if (!response.ok) {
    const status = response.status;
    const statusText = response.statusText;
    throw new Error(`Telegram API responded ${status} ${statusText}`);
  }
}

export async function notifyTelegram(input: TelegramNotifyInput): Promise<void> {
  const settings = SettingsDefaultsManager.loadFromFile(USER_SETTINGS_PATH);

  if (settings.CLAUDE_MEM_TELEGRAM_ENABLED !== 'true') {
    return;
  }

  const botToken = settings.CLAUDE_MEM_TELEGRAM_BOT_TOKEN;
  const chatId = settings.CLAUDE_MEM_TELEGRAM_CHAT_ID;
  if (!botToken || !chatId) {
    return;
  }

  const triggerTypes = splitCsv(settings.CLAUDE_MEM_TELEGRAM_TRIGGER_TYPES);
  const triggerConcepts = splitCsv(settings.CLAUDE_MEM_TELEGRAM_TRIGGER_CONCEPTS);

View on GitHub (pinned to d768ba3643)

Solutions

  1. Verify the bot token: curl https://api.telegram.org/bot<TOKEN>/getMe — a 401 means the token is wrong/revoked.
  2. Confirm chat_id by sending /start to the bot and checking getUpdates; ensure the chat_id in settings matches.
  3. If MarkdownV2 parsing fails, simplify the message or switch parse_mode; ensure escapeMarkdownV2 is applied to all dynamic text.
  4. For 429, reduce notification volume or add backoff between sends.

Example fix

# before
curl https://api.telegram.org/bot$TOKEN/sendMessage -d chat_id=$CHAT -d text=hi
# -> {"ok":false,"error_code":401,"description":"Unauthorized"}

# after — regenerate token via @BotFather, set it
export CLAUDE_MEM_TELEGRAM_BOT_TOKEN='<new-token>'
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate token/chatId shape before sending.
function telegramConfigValid(token?: string, chatId?: string): boolean {
  return /^\d+:\w{30,}$/.test(token ?? '') && /^-?\d+$/.test(chatId ?? '');
}

Type guard

function isTelegramApiError(e: unknown): boolean {
  return e instanceof Error && /Telegram API responded \d+/.test(e.message);
}

Try / catch

// notifyTelegram already wraps each send; mirror that pattern when calling directly.
try {
  await postOne(botToken, chatId, text);
} catch (e) {
  if (e instanceof Error && /Telegram API responded/.test(e.message)) {
    logger.warn('TELEGRAM', 'Telegram send failed; non-fatal', {}, e);
    return; // one failed message must not break the batch
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12). Data as JSON: /api/errors/546935d84239af6f. Report an issue: GitHub.