Skip to content

Commit fe701c5

Browse files
committed
fix(telegram): send error messages to user when command/callback handlers fail
Previously, when a command or callback query handler returned an error, the error was logged and OnError was called, but the user received no response — leaving them staring at silence. Now SendResponse is called with "❌ " + error text so the user knows the command failed and gets the error message. 3 new tests: command error, callback error, no double-send on success
1 parent c5faabc commit fe701c5

2 files changed

Lines changed: 136 additions & 0 deletions

File tree

internal/telegram/handler.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ func (h *Handler) handleCommand(msg *Message) {
278278
if h.OnError != nil {
279279
h.OnError(msg.Chat.ID, err)
280280
}
281+
// Send the error message to the user so they know the command failed.
282+
h.SendResponse(msg.Chat.ID, "❌ "+err.Error(), msg.ID)
281283
return
282284
}
283285
if resp != "" {
@@ -320,6 +322,8 @@ func (h *Handler) handleCallback(cq *CallbackQuery) {
320322
if h.OnError != nil {
321323
h.OnError(cq.Message.Chat.ID, err)
322324
}
325+
// Send the error message to the user.
326+
h.SendResponse(cq.Message.Chat.ID, "❌ "+err.Error(), cq.Message.ID)
323327
return
324328
}
325329
if resp != "" {
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package telegram
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"testing"
7+
)
8+
9+
// TestHandleCommand_ErrorSentToUser verifies that when a command handler
10+
// returns an error, the error message is sent to the user (not just logged).
11+
func TestHandleCommand_ErrorSentToUser(t *testing.T) {
12+
rec := new(requestRecorder)
13+
ts := testServer(t, rec)
14+
defer ts.Close()
15+
bot := testBot(t, ts)
16+
h := NewHandler(bot)
17+
18+
h.OnCommand = func(chatID int64, messageID int, cmd string, args string) (string, error) {
19+
return "", fmt.Errorf("simulated command failure: %s", cmd)
20+
}
21+
22+
upd := Update{
23+
ID: 1,
24+
Message: &Message{
25+
ID: 42,
26+
Chat: &Chat{ID: 123},
27+
From: &User{ID: 456},
28+
Text: "/start",
29+
Entities: []MessageEntity{
30+
{Type: "bot_command", Offset: 0, Length: 6},
31+
},
32+
},
33+
}
34+
35+
h.HandleUpdate(upd)
36+
37+
// Verify a sendMessage was sent with the error text.
38+
found := false
39+
for _, r := range rec.all() {
40+
if strings.Contains(r.Path, "sendMessage") {
41+
if strings.Contains(r.Body, "simulated command failure") {
42+
found = true
43+
break
44+
}
45+
}
46+
}
47+
if !found {
48+
t.Error("error from command handler was not sent to user")
49+
}
50+
}
51+
52+
// TestHandleCallback_ErrorSentToUser verifies that when a callback query
53+
// handler returns an error, the error message is sent to the user.
54+
func TestHandleCallback_ErrorSentToUser(t *testing.T) {
55+
rec := new(requestRecorder)
56+
ts := testServer(t, rec)
57+
defer ts.Close()
58+
bot := testBot(t, ts)
59+
h := NewHandler(bot)
60+
61+
h.OnCallbackQuery = func(chatID int64, data string) (string, error) {
62+
return "", fmt.Errorf("simulated callback failure: %s", data)
63+
}
64+
65+
upd := Update{
66+
ID: 2,
67+
CallbackQuery: &CallbackQuery{
68+
ID: "cq_test",
69+
From: &User{ID: 456},
70+
Message: &Message{
71+
Chat: &Chat{ID: 789},
72+
},
73+
Data: "test_data",
74+
},
75+
}
76+
77+
h.HandleUpdate(upd)
78+
79+
// Verify a sendMessage was sent with the error text.
80+
found := false
81+
for _, r := range rec.all() {
82+
if strings.Contains(r.Path, "sendMessage") {
83+
if strings.Contains(r.Body, "simulated callback failure") {
84+
found = true
85+
break
86+
}
87+
}
88+
}
89+
if !found {
90+
t.Error("error from callback handler was not sent to user")
91+
}
92+
}
93+
94+
// TestHandleCommand_ErrorNotSentOnSuccess verifies that successful commands
95+
// still send only the response text (not double-sending).
96+
func TestHandleCommand_ErrorNotSentOnSuccess(t *testing.T) {
97+
rec := new(requestRecorder)
98+
ts := testServer(t, rec)
99+
defer ts.Close()
100+
bot := testBot(t, ts)
101+
h := NewHandler(bot)
102+
103+
h.OnCommand = func(chatID int64, messageID int, cmd string, args string) (string, error) {
104+
return "ok response", nil
105+
}
106+
107+
upd := Update{
108+
ID: 3,
109+
Message: &Message{
110+
ID: 99,
111+
Chat: &Chat{ID: 111},
112+
From: &User{ID: 222},
113+
Text: "/status",
114+
Entities: []MessageEntity{
115+
{Type: "bot_command", Offset: 0, Length: 7},
116+
},
117+
},
118+
}
119+
120+
h.HandleUpdate(upd)
121+
122+
// Count sendMessage calls — should be exactly 1 (for the response).
123+
sendCount := 0
124+
for _, r := range rec.all() {
125+
if strings.Contains(r.Path, "sendMessage") {
126+
sendCount++
127+
}
128+
}
129+
if sendCount != 1 {
130+
t.Errorf("expected 1 sendMessage, got %d (should not double-send on success)", sendCount)
131+
}
132+
}

0 commit comments

Comments
 (0)