Skip to content

Report unrecognized Twitch ban and timeout refusals as rejections - #1752

Merged
kevmo314 merged 1 commit into
mainfrom
claude/eager-dijkstra-hdrup8
Oct 31, 2026
Merged

kevmo314 merged 1 commit into
mainfrom
claude/eager-dijkstra-hdrup8

Conversation

@kevmo314

Copy link
Copy Markdown
Contributor

Problem

Error reporting logged this:

HTTP POST /ban returned 500: provider returned HTTP 400

Twitch rejected a ban with a 400 whose message wasn't on writeBan's list of known phrasings ("user is already banned", "user may not be banned", …). Anything off that list was returned as a plain HTTPError and reported as an internal error. Provider text is redacted, so the exact wording isn't in the log. The ban action is offered on every chat message, including the streamer's own and bots', so a refusal worded in a new way is the likely cause. #1747 already made unban treat any non-empty 400 as a refusal, but ban and timeout still used the strict list.

Fix

The fix makes a 400 from Twitch a refusal unless the request itself was malformed:

  • Timeout limits are checked before calling Twitch (cmd/chat.go). Length must be a whole number of seconds from 1 to 1,209,600, and the reason at most 500 characters. Out-of-range input gets invalid-argument without a call to Twitch. Ban and unban requests contain only resolved IDs.
  • Any other non-empty 400 is a refusal (internal/clients/twitch/chat.go). This now applies to ban, timeout and unban alike. The client gets failed-precondition with "Twitch rejected this ban/timeout/unban request." and never sees the raw text. Known phrasings still get their specific messages.
  • Malformed requests still alert. If the message mentions a parameter, or says something is required, malformed or invalid, it stays a 500. That way a bug in how the agent builds the request is still reported.

Tradeoff: the malformed-request check matches Twitch's usual wording, not a documented contract. If Twitch reports a malformed request in other words, it shows up as a refusal instead of an alert.

Tests

  • Updated the two TestTwitchModerationRejectionReporting cases that pinned unrecognized ban wording to a 500.
  • Added cases for an unrecognized timeout refusal, an empty 400 body, and malformed-request wording for ban, timeout and unban.
  • Added TestTwitchTimeoutBoundsCheckedLocally, which checks that out-of-range length, a fractional length and an over-long reason never reach Twitch.

go test ./cmd ./internal/... passes except the internal/youtube live tests, which need youtube.com (blocked in the sandbox where this was developed). The Twitch limits are from memory of the API docs: dev.twitch.tv was also blocked, so they weren't rechecked.


Generated by Claude Code

Twitch answered a ban with HTTP 400 and wording outside the recognized
list, so the agent raised a 500 alert for what was Twitch refusing the
action. Unban already treated any non-empty 400 message as a refusal,
because its request carries nothing the caller controls.

Ban and timeout requests carry only resolved IDs plus the timeout
length and reason, which are now checked against Twitch's documented
bounds before sending. With that, a 400 can only be a refusal unless
Helix describes a malformed request (a missing, required, malformed or
invalid parameter), which stays an internal error so agent bugs still
alert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzdqAWrbTMdtJutmK41coy
@kevmo314
kevmo314 merged commit 0cf4831 into main Oct 31, 2026
8 checks passed
@kevmo314
kevmo314 deleted the claude/eager-dijkstra-hdrup8 branch October 31, 2026 04:47
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.

2 participants