thedotmack/claude-mem · warning

Failed to send Telegram notification

Error message

Failed to send Telegram notification

What it means

TelegramNotifier posts one message per matching observation via postOne (Telegram Bot API sendMessage). This warning fires when an individual send fails — network error, 400 for malformed text or a bad chat id, 401 for an invalid bot token, 403 when the bot was never started in the chat, or 429 rate limiting — and the loop continues with remaining observations. One failure never aborts the batch.

Source

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

    return;
  }

  const { observations, observationIds, project, memorySessionId } = input;
  for (let i = 0; i < observations.length; i++) {
    const obs = observations[i];
    const matchesType = triggerTypes.includes(obs.type);
    const matchesConcept = obs.concepts.some(c => triggerConcepts.includes(c));
    if (!matchesType && !matchesConcept) {
      continue;
    }

    const observationId = observationIds[i];
    try {
      const text = formatMessage(obs, project, memorySessionId, observationId);
      await postOne(botToken, chatId, text);
    } catch (error) {
      const err = error instanceof Error ? error : new Error(String(error));
      logger.warn('TELEGRAM', 'Failed to send Telegram notification', {
        observationId,
        project,
        memorySessionId,
        type: obs.type,
      }, err);
    }
  }
}

View on GitHub (pinned to e2d1df569a)

Solutions

  1. Read the logged error: 401 → fix the bot token; 400/403 → verify chatId and that the bot was started in that chat; 429 → reduce notification frequency.
  2. Truncate or split message text to stay under Telegram's 4096-character limit.
  3. Verify credentials directly: curl 'https://api.telegram.org/bot<TOKEN>/sendMessage?chat_id=<ID>&text=ping'.
  4. Allow egress to api.telegram.org if a firewall or proxy is blocking it.

Example fix

// before: long observations exceed Telegram's 4096-char limit
await postOne(botToken, chatId, text);
// after: clamp the payload before sending
await postOne(botToken, chatId, text.slice(0, 4096));
Defensive patterns

Strategy: retry

Validate before calling

// verify credentials once before enabling Telegram notifications
const res = await fetch(`https://api.telegram.org/bot${botToken}/getMe`);
if (!res.ok) throw new Error(`invalid bot token (HTTP ${res.status})`);
// then confirm the chat accepts the bot
const send = await fetch(`https://api.telegram.org/bot${botToken}/sendMessage?chat_id=${chatId}&text=ping`);

Try / catch

for (const obs of matching) {
  try {
    await postOne(botToken, chatId, clampMessage(formatMessage(obs)));
  } catch (e) {
    if ((e as Error).message.includes('429')) {
      await sleep(retryAfterMs(e) ?? 1000); // honor retry_after, then retry once
      await postOne(botToken, chatId, clampMessage(formatMessage(obs)));
    }
    // other errors: log and continue — never abort the batch
  }
}

Prevention

When it happens

Trigger: await postOne(botToken, chatId, text) throws: invalid or revoked bot token, wrong chatId, message text exceeding Telegram's 4096-character limit, 429 rate limiting during bursts of observations, or no network egress to api.telegram.org.

Common situations: Revoked bot token; user never pressed Start in the chat (403 chat not found); corporate firewall blocking Telegram; a long observation blowing the length limit; bursts of observations tripping rate limits.

Related errors


AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20). Data as JSON: /api/errors/5b8d35397a95cffd. Report an issue: GitHub.