Skip to content

fix(tgbot): suppress 'message not modified' log spam from refresh buttons - #6340

Open
BlindMaster24 wants to merge 1 commit into
MHSanaei:mainfrom
BlindMaster24:fix/tgbot-not-modified-spam
Open

fix(tgbot): suppress 'message not modified' log spam from refresh buttons#6340
BlindMaster24 wants to merge 1 commit into
MHSanaei:mainfrom
BlindMaster24:fix/tgbot-not-modified-spam

Conversation

@BlindMaster24

Copy link
Copy Markdown

Summary

Suppress noisy "message is not modified" warnings in Telegram bot edit calls when users click Refresh buttons.

Why

When users click 🔄 Refresh in the Telegram bot (usage, client info, IP logs, onlines), editMessageText and editMessageReplyMarkup are always called even when the data hasn't changed. Telegram returns a 400 error (message is not modified), which was logged as Warning — cluttering the logs on every single refresh click.

Type of change

  • Bug fix
  • New feature
  • Refactoring (no behavior change)
  • Documentation
  • Tests only
  • Build / CI / tooling
  • Other

Areas affected

  • Frontend (UI / panel pages)
  • Backend (API endpoints, login, settings)
  • Xray config generation
  • Subscription (share links / Clash / JSON)
  • Statistics / traffic counters
  • Database / migrations
  • Install / upgrade script
  • Docker image
  • Multi-node (sub-nodes)
  • Telegram bot

How was this tested?

  • Unit test TestIsTelegramNotModifiedError verifies the helper correctly identifies "not modified" and "No fields to modify" errors while rejecting unrelated errors.
  • gofmt passes. Full go test requires GCC (CGo/SQLite) which is available on CI.

Screenshots / recordings

N/A

Breaking changes

None

Checklist

  • I tested the change locally and confirmed the described behavior.
  • I added or updated tests for the new behavior.
  • go build ./... and the test suite pass locally. (requires GCC/MinGW — CI will verify)
  • For frontend changes: npm run lint, npm run typecheck, and npm run build pass.
  • I updated the Wiki / README / API docs if user-facing behavior changed.
  • My commits follow the project's existing message style.
  • I have no unrelated changes mixed into this PR.

@BlindMaster24
BlindMaster24 force-pushed the fix/tgbot-not-modified-spam branch from 829d96b to f4847b7 Compare August 27, 2026 16:39
Comment on lines +241 to +243
// isTelegramNotModifiedError checks if the Telegram API returned a "message
// not modified" error, which happens when editMessageText or
// editMessageReplyMarkup is called with content identical to the existing message.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Nit — comment block exceeds the repo's 2-line maximum

This new doc comment is 3 lines. CLAUDE.md hard rule:

Comments in committed Go/TS: 2 lines MAX per comment block. Make the name carry the meaning first and rename rather than annotate; spend the 2 lines on the why a name cannot hold — an invariant, an issue number, a non-obvious constraint. Exempt: //go:build, //go:generate, and other directives.

isTelegramNotModifiedError already carries the what, and the two call sites at L212-L217 show where it applies, so the third line is restatement. No linter catches this one — it has to be done by hand.

Suggested change
// isTelegramNotModifiedError checks if the Telegram API returned a "message
// not modified" error, which happens when editMessageText or
// editMessageReplyMarkup is called with content identical to the existing message.
// Telegram answers a no-op edit with a 400 whose description carries this text;
// a refresh tap that changed nothing is not an operator-visible failure.

Comment on lines +9 to +30
func TestIsTelegramNotModifiedError(t *testing.T) {
tests := []struct {
name string
err error
want bool
}{
{"nil error", nil, false},
{"not modified", errors.New("Bad Request: message is not modified"), true},
{"No fields to modify", errors.New("Bad Request: No fields to modify"), true},
{"unrelated error", errors.New("Bad Request: message to edit not found"), false},
{"network error", errors.New("connection reset"), false},
{"empty string", errors.New(""), false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := isTelegramNotModifiedError(tt.err)
if got != tt.want {
t.Errorf("isTelegramNotModifiedError(%v) = %v, want %v", tt.err, got, tt.want)
}
})
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Nit — the test pins the helper, not the fix

This test calls isTelegramNotModifiedError directly with hand-built errors.New(...) strings. It never invokes editMessageCallbackTgBot or editMessageTgBot, and never asserts that a not-modified error stops reaching logger.Warning — which is the behaviour the PR title promises.

Delete just the guard at L212-L218 or L232-L238 and leave the helper in place: Go allows an unused package-level function, so this test stays green while the log spam is fully back. CLAUDE.md:

A test must fail without its fix. Write it, revert the fix, watch it go red, restore.

The pieces to pin it are already in the package: bot is built with telego.WithAPIServer(...) (tgbot.go:430), so an httptest.Server returning Telegram's message is not modified body can back it, and logger.GetLogs(c int, level string) (logger.go:220) can assert no Warning-level entry was recorded. That version goes red when either guard is removed; this one does not.

No suggestion block — this is a new test, not an edit to this one.

@github-actions

Copy link
Copy Markdown
Contributor

Code review

No blocking issues0 🔴 / 2 🟡 / 0 🟣

Reviewed head: 829d96b26a8de81a1decf4ed4b49b9f2b83f97fa

Both nits are posted inline:

  1. 🟡 tgbot_send.go:241-243 — the new doc comment is 3 lines; CLAUDE.md caps comment blocks at 2. Suggestion attached.
  2. 🟡 tgbot_send_test.go:9-30TestIsTelegramNotModifiedError exercises the helper in isolation. Removing either guard at the call sites leaves it green, so it does not pin the log-spam fix it was written for.

⚠️ No CI has run on this head

CI, CodeQL Advanced and Release 3X-UI are all completed / action_required on 829d96b2 — the first-time-contributor approval gate, so they never executed. go-test, race, lint and vulncheck have produced no result for this change; the only completed checks are issue-analyst, mention and resolve-conflicts, all skipped. A maintainer needs to approve the workflow run before this merges.

Coverage

  • Diff: 2 files, +44/-0, both in internal/web/service/tgbot/. Read in full.
  • Guard logic: return is the last statement in both editMessageCallbackTgBot (tgbot_send.go:212-219) and editMessageTgBot (:232-239) — nothing made unreachable, no cleanup skipped. strings already imported (:6); logger.Debug(args ...any) exists (internal/logger/logger.go:139).
  • Substring match: verified against telego v1.11.2 upstream — telegoapi.Error.Error() formats the Telegram description, so the guard does fire. chat title is not modified / chat description is not modified also contain not modified, but come from setChatTitle/setChatDescription, which this package never calls. No fields to modify matches no Bot API description I could confirm — likely a dead branch, harmless.
  • Callers: all call sites of the two edit helpers ignore the return; no retry, alert or branch reads the log. No behavioural regression beyond the intended level change.
  • Not applicable, checked: no new g.POST/g.GET, so no endpoints.ts / make gen / StructAllow / docs/public/openapi.json chain; no model or schema change, so no migration; no inbound/client state change, so no runtime.Runtime dispatch; no i18n key; nothing on the wire (Xray config, share links, subscriptions, mtg TOML) changes.
  • Unverified: nothing was built or executed here (PR code must not run under this token), and CI produced no result on this head, so compilation and the test suite are unconfirmed by any run. The telego error-format claim comes from upstream source at the pinned tag, not from a local module cache — that directory does not exist in this environment.

… calls

When users click Refresh buttons in the Telegram bot (usage_refresh,
client_refresh, ips_refresh, onlines_refresh), editMessageText and
editMessageReplyMarkup are always called even when the content has not
changed. Telegram returns a 400 "message is not modified" error which
was logged as Warning, cluttering the logs on every refresh click.

Add isTelegramNotModifiedError helper that detects this specific
Telegram API error and logs it at Debug level instead of Warning.
@BlindMaster24
BlindMaster24 force-pushed the fix/tgbot-not-modified-spam branch from f4847b7 to 5ab9042 Compare August 27, 2026 16:47
@BlindMaster24

Copy link
Copy Markdown
Author

@claude done!

@BlindMaster24

Copy link
Copy Markdown
Author

@MHSanaei ?

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