Skip to content

fix(telegram): guard against empty renders and fix misleading example (#26)#28

Merged
fxthiry merged 1 commit intorelease/1.1.1from
fix/gh-26-empty-telegram-text
Apr 15, 2026
Merged

fix(telegram): guard against empty renders and fix misleading example (#26)#28
fxthiry merged 1 commit intorelease/1.1.1from
fix/gh-26-empty-telegram-text

Conversation

@fxthiry
Copy link
Copy Markdown
Owner

@fxthiry fxthiry commented Apr 15, 2026

Summary

Fixes #26. When a user copies the example config pattern (title: \"{{ title | default('Alert') }}\" / body: \"{{ body }}\"), both templates resolve to empty strings at render time because VictoriaLogs events do not carry title / body fields. Telegram's parse_mode: HTML default then receives a near-empty payload (<b></b>\n) and responds HTTP 400 Bad Request. The alert is silently lost.

Two coupled fixes:

  • Runtime guard in TelegramNotifier::prepare_text. If the rendered text is empty, whitespace-only, or contains no text after stripping HTML tags, substitute a priority-ordered fallback and emit a structured warn!. Priority: <b>{title}</b> if title non-empty, else Alert: {rule_name}, else (valerter alert, empty render). Title and rule_name are HTML-escaped and the title is capped to stay under Telegram's 4096 codepoint limit once wrapped.

  • Honest example in config/config.example.yaml. New comment block separates "variables available inside the template" (VL event fields, rule_name, log_timestamp*) from "template output keys" (title, body, body_html, accent_color). The default_alert entry switches to title: "{{ rule_name }}" and body: "{{ _msg }}" so it renders non-empty content out of the box on any VL event.

Test plan

  • cargo test --lib — 429 passed (baseline 415 + 14 new: 11 from initial TDD + 3 from review patches)
  • cargo clippy --all-targets --all-features -- -D warnings — clean
  • cargo run --bin valerter -- --validate -c config/config.example.yaml — exit 0
  • Smoke-test live once merged with fix(templates): accept dotted VictoriaLogs fields in templates (#25) #27 on release/1.1.1 (prod-test-telegram config + broken template repro)

Review hints

Adversarial review flagged three issues that are patched in this PR (HTML injection via title/rule_name in the fallback, truncate breaking mid-tag on long titles, em-dash in a user-facing string). See _bmad-output/implementation-artifacts/deferred-work.md for seven follow-up items explicitly deferred.

Targeted at release/1.1.1 so it can be bundled with #27 and validated by the reporter before tagging v1.1.1.

…#26)

VictoriaLogs events don't carry `title` / `body` fields. When a user copies
the example config verbatim, `{{ title }}` and `{{ body }}` at the outer
template layer resolve to empty strings. Telegram's `parse_mode: HTML`
default then receives `"<b></b>\n"` after `DEFAULT_BODY_TEMPLATE` renders,
and responds 400 Bad Request. The alert is lost.

Two coupled fixes:

- `TelegramNotifier::prepare_text` now runs a `fallback_if_empty` guard:
  if the rendered text is empty, whitespace-only, or contains no text after
  stripping HTML tags, substitute with a priority-ordered fallback
  (`<b>{title}</b>` if title non-empty, else `Alert: {rule_name}`, else
  `"(valerter alert, empty render)"`) and emit a structured `warn!` with
  `rule_name`, `notifier_name`, and the matching reason. Title and
  rule_name are HTML-escaped and the title is capped to stay under
  Telegram's 4096 codepoint limit once wrapped.

- `config/config.example.yaml` now separates "variables available inside
  the template (VL fields + rule_name + log_timestamp)" from "template
  output keys (title, body, body_html, accent_color)". The default_alert
  example switches to `title: "{{ rule_name }}"` and `body: "{{ _msg }}"`
  so it renders non-empty content out of the box on any VL event.
@fxthiry fxthiry merged commit f38faa7 into release/1.1.1 Apr 15, 2026
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.

1 participant