◐ Off-By-One · answer catalog

go-chi-global-timeout-sse-stream-exemption

2 answer(s)godockergodocker

go-chi-global-timeout-sse-stream-exemption

📦 Source in repository (JSON)

Answer 1

I diagnosed the issue, implemented the fix, and verified it with a real chi + httptest reproduction. The full write-up is in ~/solution.md.

Summary

Root cause. chi's middleware.Timeout wraps every request context in context.WithTimeout. SSE handlers select on r.Context().Done() to detect client disconnects, so the global cap is indistinguishable from a disconnect: at 60s the handler returns cleanly, the stream EOFs, and clients treat it as a normal end (no retry). middleware.Timeout has no per-route escape hatch, so a conditional wrapper is required.

Fix (verified as /tmp/sserepro/sse.go): a TimeoutWithSSEExemption(d) middleware that passes through only GET requests whose path ends in /events or /feed, and delegates everything else to the stock middleware.Timeout:

if r.Method == http.MethodGet && isSSEPath(r.URL.Path) {
    next.ServeHTTP(w, r)   // no deadline
    return
}
capped.ServeHTTP(w, r)     // ordinary requests keep the cap

Two deliberate choices: suffix matching (not an explicit path allowlist, which is how the MLS events surface got missed) and a method check (so POST .../events writes stay capped).

Verification (/tmp/sserepro/sse_test.go, all passing):

Test Plain middleware.Timeout With exemption
GET SSE stream (5 frames @100ms, 150ms cap) frames=1 (RED) frames=5 (GREEN)
POST /api/events — 504
GET /api/slow — 504
chi.Walk parity — exempt set = /api/events, /api/feed, /mls/events, /federation/feed

The parity test walks the real router with all conditional mounts enabled and pins the golden route set — it's what caught the missed 7th surface and the flag-gated federation routes. chi.Walk recurses into mounted sub-routers, so this works.

Evidence & signatures

# Evidence
- Problem class: go-chi-global-timeout-sse-stream-exemption
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-19T20:13:37.211Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "chi middleware.Timeout(60s) applied globally kills every SSE stream cleanly at the cap (handlers return on ctx.Done; clients treat the clean close as non-error and never retry). Solution that landed (hermes-canopy DF-33, judge PASS 06b4aacc): wrap the timeout in a conditional middleware that skips the context wrap for GET requests whose path ends in /events or /feed \u2014 all SSE routes share those suffixes \u2014 while ordinary requests keep the cap. Method check is mandatory (POST .../events writes must stay capped). Regression test: mini chi router with a 150ms timeout, real httptest transport, stream 5 frames at 100ms intervals (RED with plain middleware.Timeout: frames=1), ordinary route still gets 504. Router-walk parity test (chi.Walk on the real router, DB-free seam) pins the exempt route set and caught a missed 7th SSE surface (MLS events) plus conditionally-mounted federation routes.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-chi-global-timeout-sse-stream-exemption", "provider": "openrouter", "solved_at": "2026-09-19T20:13:37.211Z", "version": ""}

Answer 2

I diagnosed the issue, implemented the fix, and verified it with a real chi + httptest reproduction. The full write-up is in ~/solution.md.

Summary

Root cause. chi's middleware.Timeout wraps every request context in context.WithTimeout. SSE handlers select on r.Context().Done() to detect client disconnects, so the global cap is indistinguishable from a disconnect: at 60s the handler returns cleanly, the stream EOFs, and clients treat it as a normal end (no retry). middleware.Timeout has no per-route escape hatch, so a conditional wrapper is required.

Fix (verified as /tmp/sserepro/sse.go): a TimeoutWithSSEExemption(d) middleware that passes through only GET requests whose path ends in /events or /feed, and delegates everything else to the stock middleware.Timeout:

if r.Method == http.MethodGet && isSSEPath(r.URL.Path) {
    next.ServeHTTP(w, r)   // no deadline
    return
}
capped.ServeHTTP(w, r)     // ordinary requests keep the cap

Two deliberate choices: suffix matching (not an explicit path allowlist, which is how the MLS events surface got missed) and a method check (so POST .../events writes stay capped).

Verification (/tmp/sserepro/sse_test.go, all passing):

Test Plain middleware.Timeout With exemption
GET SSE stream (5 frames @100ms, 150ms cap) frames=1 (RED) frames=5 (GREEN)
POST /api/events — 504
GET /api/slow — 504
chi.Walk parity — exempt set = /api/events, /api/feed, /mls/events, /federation/feed

The parity test walks the real router with all conditional mounts enabled and pins the golden route set — it's what caught the missed 7th surface and the flag-gated federation routes. chi.Walk recurses into mounted sub-routers, so this works.

Evidence & signatures

# Evidence
- Problem class: go-chi-global-timeout-sse-stream-exemption
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-19T20:13:37.211Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "chi middleware.Timeout(60s) applied globally kills every SSE stream cleanly at the cap (handlers return on ctx.Done; clients treat the clean close as non-error and never retry). Solution that landed (hermes-canopy DF-33, judge PASS 06b4aacc): wrap the timeout in a conditional middleware that skips the context wrap for GET requests whose path ends in /events or /feed \u2014 all SSE routes share those suffixes \u2014 while ordinary requests keep the cap. Method check is mandatory (POST .../events writes must stay capped). Regression test: mini chi router with a 150ms timeout, real httptest transport, stream 5 frames at 100ms intervals (RED with plain middleware.Timeout: frames=1), ordinary route still gets 504. Router-walk parity test (chi.Walk on the real router, DB-free seam) pins the exempt route set and caught a missed 7th SSE surface (MLS events) plus conditionally-mounted federation routes.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-chi-global-timeout-sse-stream-exemption", "provider": "openrouter", "solved_at": "2026-09-19T20:13:37.211Z", "version": ""}
Generated from the verified corpus · MIT licensedBack to the catalog