Skip to content

fix(tasklist): prevent editMessageText crash when prompt exceeds Telegram 4 096-byte limit#148

Open
aborovsky wants to merge 6 commits into
grinev:mainfrom
aborovsky:fix/tasklist-prompt-truncation
Open

fix(tasklist): prevent editMessageText crash when prompt exceeds Telegram 4 096-byte limit#148
aborovsky wants to merge 6 commits into
grinev:mainfrom
aborovsky:fix/tasklist-prompt-truncation

Conversation

@aborovsky

@aborovsky aborovsky commented Jun 9, 2026

Copy link
Copy Markdown

Description of changes

  • Added truncateToByteLength(text, maxBytes) utility that measures string size in UTF-8 bytes (via TextEncoder) and binary-searches for the longest safe prefix, with a surrogate-pair boundary guard to prevent malformed Unicode output.
  • formatTaskDetails() now passes truncateToByteLength(task.prompt, 3800) instead of the raw task.prompt to the t("tasklist.details", …) i18n template before calling ctx.editMessageText().
  • The existing truncateText() (character-count based) is unchanged and still used by formatTaskButtonLabel.

Why 3 800 bytes?
4 096 (Telegram hard limit) − 230 (template chrome: title, labels, schedule, cron, timezone, timestamps, run count) − 66 (safety margin) = 3 800.
A comment in the code documents this derivation and notes that non-English locales may need recalculating.

Rebase note: After the upstream structure refactor (PR #149), formatTaskDetails() moved from src/bot/commands/tasklist.ts to src/bot/callbacks/scheduled-task-callback-handler.ts. The truncateToByteLength() function is placed alongside it in that file.

Closes issue (optional)

How it was tested

Three new unit tests added to tests/bot/commands/tasklist.test.ts:

Test What it verifies
truncates oversized ASCII prompt … 5 000-char ASCII prompt is truncated; Buffer.byteLength(text, "utf8") ≤ 4 096
truncates oversized multi-byte prompt … 1 200 🚀 emojis (4 800 UTF-8 bytes) are truncated; byte-length assertion passes; at least one emoji survives
does not truncate prompt that fits within the byte limit Short prompt passes through unchanged, no appended

All 1002 tests pass (vitest 3.2.6).

Checklist

  • PR title follows Conventional Commits: fix(tasklist): prevent editMessageText crash when prompt exceeds Telegram 4 096-byte limit
  • This PR contains one logically complete change
  • Branch is rebased on the latest main
  • npm run lint, npm run build, and npm test — changes are isolated to one function addition + one call-site change; no new imports or config changes
  • No OS-sensitive behaviour introduced

@grinev

grinev commented Jun 15, 2026

Copy link
Copy Markdown
Owner

@aborovsky could you please do rebase

@aborovsky aborovsky force-pushed the fix/tasklist-prompt-truncation branch from 10e6290 to c4d2cf4 Compare June 18, 2026 03:42
@grinev

grinev commented Jun 18, 2026

Copy link
Copy Markdown
Owner

@aborovsky
Error can be still appeared after this fix.
The message also includes dynamic fields like project path, model, schedule summary, cron, timezone, dates, and localized labels. These fields can vary in byte length, especially in non-English locales.
Because of that, lowering the fixed limit to 3500 would be a useful quick improvement, but it still does not fully guarantee that the final Telegram message stays under 4096 bytes.

A safer solution would be to calculate the prompt budget dynamically in formatTaskDetails():

  1. Build the details message with an empty prompt.
  2. Measure its UTF-8 byte length.
  3. Calculate promptBudget = 4096 - chromeBytes - safetyMargin.
  4. Truncate the prompt using that budget.
  5. Optionally add a fallback if the non-prompt part is already too long.

This would avoid relying on a fixed number like 3800 or 3500, and would make the fix reliable across locales and longer task metadata.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(tasklist): task detail view silently fails when prompt exceeds ~3 870 chars (Telegram 4 096-byte editMessageText limit)

2 participants