Skip to content

bug(telegram): non-image document attachments are silently dropped or trigger "unexpected error" #539

@Austin5925

Description

@Austin5925

Problem / 问题

Sending non-image documents (PDF, DOCX, TXT, ZIP, etc.) to a CodePilot
Telegram bot produces inconsistent, broken behavior. Although CodePilot's
main chat UI input supports file attachments (per #11, implemented via
the @file/@directory mention feature in #508), the Telegram bridge
adapter is a separate code path that has not been updated
— it still
only handles photos and image-MIME documents.

向 CodePilot Telegram bot 发送非图片类型文档时(PDF、DOCX、TXT、ZIP 等),
观察到两种不一致的失败模式。需要说明的是,CodePilot 主聊天界面的输入框
是支持文件附件的(见 #11 的回复,由 #508 实现的 @file 功能),但
Telegram 桥的 adapter 走的是另一条独立代码路径,没有同步更新

Reproduction / 复现

Scenario / 场景 Image / 图片 File / 文件
A. Image + file sent together / 同时发送图片和文件 ✅ Analyzed and replied / 正常分析回复 ❌ Bot replies "An unexpected error occurred." / 回复"An unexpected error occurred."
B. File alone (after scenario A) / 单独再发文件 ❌ Silent — no response at all / 完全无响应
C. Image alone / 单独发图片 (control / 对照) ✅ Works / 正常

Steps:

  1. Configure CodePilot Telegram bridge with a valid bot token, ensure bot is enabled.
  2. Scenario A: in Telegram DM, attach a photo and a PDF together (e.g. via "Send media" → multi-select), send.
  3. Scenario B: after the above, send only a PDF (no caption, no image).
  4. Scenario C (control): send only an image.

Root cause / 根因

src/lib/bridge/adapters/telegram-adapter.ts:551-600 — inbound dispatch only recognizes images:

const hasPhoto = m.photo && m.photo.length > 0;
const hasDocImage = m.document && this.isDocumentImage(m.document);
const hasMedia = hasPhoto || hasDocImage;

isDocumentImage() (line 624-632) accepts only image/jpeg|png|gif|webp. PDF / DOCX / TXT / ZIP all return false.

  • Scenario B (silent drop) — confirmed by code reading. A standalone document with no caption hits the else branch at line 597-600: // Unhandled message type — skipmarkUpdateProcessed() returns without enqueue. No turn, no reply.
  • Scenario A ("unexpected error") — likely path. flushMediaGroup (line 791-805) similarly skips non-image documents in albums without adding to the rejections list. The exact source of the "unexpected error" message is not pinned down by code reading alone (the catch-all comes from error-classifier.ts:413); it appears to come from a downstream code path that does not gracefully handle the unhandled-document case during mixed-media processing.

The download infrastructure (downloadFileById in telegram-media.ts:193+) already supports arbitrary file types — only the dispatch gates filter them out.

Why it matters

claude-client.ts:1037-1048 already has full end-to-end support for non-image attachments — it persists them to disk and prompts Claude to read via the Read tool:

const nonImageFiles = files.filter(f => !isImageFile(f.type));
if (nonImageFiles.length > 0) {
  const savedPaths = getUploadedFilePaths(nonImageFiles, workDir);
  // Tells Claude to read attached file via Read tool
}

The Feishu adapter handles generic file msg_type via inbound.ts:117-148. The Telegram bridge is the outlier on this code path. The symptom is also more confusing than a silent drop because mixed-media albums emit an error reply instead of just skipping.

Proposed fix / 修复方案

  1. Single-document path: add a m.document && !isDocumentImage(m.document) && isDocumentEnabled() branch in the dispatch that downloads via downloadFileById and enqueues with FileAttachment carrying doc.file_name + doc.mime_type.
  2. Album path: in flushMediaGroup, handle non-image documents in the same loop instead of silently skipping them.
  3. Settings (mirror existing image_ pattern)*:
    • bridge_telegram_document_enabled (default true)
    • bridge_telegram_max_document_size (default 20 MB — Telegram Bot API ceiling)

PR incoming.

Workaround / 临时方案

Use the Feishu bridge for documents — Feishu's inbound.ts correctly handles generic file msg_type.

Related / 相关

Environment

  • CodePilot version: 0.54.0 (main HEAD)
  • Telegram clients: Desktop and iOS
  • Bot configured via standard @BotFather flow

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions