chenhg5/cc-connect · warning
max: chat action %s: status %d
Error message
max: chat action %s: status %d
What it means
sendChatAction posts a presence action (typing_on / mark_seen) to MAX at /chats/{id}/actions; this error is returned when MAX answers with a non-2xx status. It is deliberately best-effort: StartTyping and the re-arm goroutine discard it (errors are only logged at debug level), so it normally surfaces only in tests or when calling sendChatAction directly. It indicates the typing/seen indicator request was rejected by MAX.
Source
Thrown at platform/max/max.go:716
}
url := p.apiBase + "/chats/" + chatID + "/actions"
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
if err != nil {
return err
}
p.setAuth(req)
req.Header.Set("Content-Type", "application/json")
resp, err := p.client.Do(req)
if err != nil {
slog.Debug("max: chat action failed", "chat", chatID, "action", action, "err", err)
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 300 {
respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 256))
slog.Debug("max: chat action non-2xx",
"chat", chatID, "action", action, "status", resp.StatusCode, "body", string(respBody))
return fmt.Errorf("max: chat action %s: status %d", action, resp.StatusCode)
}
return nil
}
// FormattingInstructions implements core.FormattingInstructionProvider.
// The engine appends this to the agent system prompt so Claude uses only
// MAX-supported markdown syntax.
func (p *Platform) FormattingInstructions() string {
return `Formatting rules for MAX messenger:
- **bold** and _italic_ are supported
- Inline code: ` + "`code`" + ` and fenced code blocks (` + "```" + `) are supported
- Bullet lists with - or * are supported as plain text
- Do NOT use headers (# ## ###)
- Do NOT use horizontal rules (--- or ***)
- Do NOT use tables
- Do NOT use HTML tags
Keep responses concise and use plain text where possible.`
}View on GitHub (pinned to 4000b2338a)
Solutions
- Enable debug logging and read the logged respBody (slog "max: chat action non-2xx") — it shows MAX's specific reason (401 auth, 403 permission, 404 chat, 429 rate limit).
- Refresh the bot token if 401; verify the bot is still a member of the chat if 403/404.
- For 429, lengthen typingInterval so the re-arm ticker sends fewer requests.
- Since the return value is ignored in StartTyping, treat this as non-fatal for the message flow; only fix it if typing indicators matter to your users.
- Verify the chatID embedded in the session key is current — reconstruct from a fresh incoming message if it is stale.
Example fix
// before (error silently discarded)
_ = p.sendChatAction(tickCtx, rctx.chatID, "typing_on")
// after: surface and adapt to rate limits
if err := p.sendChatAction(tickCtx, rctx.chatID, "typing_on"); err != nil {
slog.Warn("max: typing indicator failed", "chat", rctx.chatID, "err", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Validate inputs and session freshness before re-arming typing
func canSendChatAction(chatID string) bool {
return chatID != ""
} Try / catch
if err := p.sendChatAction(ctx, chatID, "typing_on"); err != nil {
// best-effort: log at debug, never fail the message flow
slog.Debug("max: chat action failed", "chat", chatID, "err", err)
} Prevention
- Always treat chat-action errors as non-fatal; typing indicators are cosmetic.
- Check the debug log body for 401/403/404/429 and fix the underlying cause (token, membership, rate).
- Space typing_on re-arms at least a few seconds apart to avoid 429s.
- Reconstruct reply contexts from fresh incoming messages so chatIDs stay valid.
When it happens
Trigger: StartTyping (or the anonymous ticker callback) firing when the chatID is invalid/deleted, the bot lacks permission for that chat, the action string is not accepted by the API version, or MAX is returning 4xx/5xx (rate limit 429, auth 401, server 500).
Common situations: Typing indicator re-armed after the chat was deleted or the bot was removed; stale chat IDs from restored sessions; expired bot tokens; MAX rate-limiting rapid re-arming of typing_on; calling TestUploadKindPropagation-style tests without a reachable/authorized API.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- max: edit message: HTTP %d: %s
- upload url: HTTP %d: %s
- upload url: empty url in response
- cdn upload: HTTP %d: %s
- poll: HTTP %d: %s
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/99f2220c1fac20d4.
Report an issue: GitHub.