mirror of
https://github.com/open-webui/terminals.git
synced 2026-11-05 01:37:21 +00:00
[GH-ISSUE #24] issue: _proxy_request returns 500 on stale keep-alive connections (RemoteProtocolError not retried) #7
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
open-webui/terminals#7
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @Classic298 on GitHub (May 13, 2026).
Original GitHub issue: https://github.com/open-webui/terminals/issues/24
Summary
When the orchestrator's pooled HTTP connection to an upstream user-container instance is closed server-side after a long-lived keep-alive session, the next request the orchestrator tries to make on that connection fails with
httpx.RemoteProtocolError: Server disconnected without sending a response.and is surfaced as a 500 to the caller (Open WebUI). The next request opens a fresh connection and succeeds, so the failure is transient — but it produces visible 500s in the Open WebUI UI any time a connection ages out mid-poll.Environment
ghcr.io/open-webui/terminals:latest(Docker backend)ghcr.io/open-webui/open-terminal:latestGET /p/<policy>/portsevery 5s for the PortList component, which means a long-lived connection accumulates many requests.Observed
A connection that had handled ~50 requests on the same TCP socket gets closed server-side by uvicorn (presumably idle timeout or max-keepalive-requests). httpx writes the next request to the now-dead connection:
5 seconds later, on the next poll, a fresh TCP connection is opened (
connect_tcp.started) and the same request returns 200. Steady state resumes.Root cause
In
terminals/routers/proxy.py:153-175,_proxy_requestretries only onhttpx.ConnectError/httpx.ConnectTimeout:It does not retry on
httpx.RemoteProtocolError(orhttpx.ReadError), which is the textbook signature of a stale-keepalive race in HTTP/1.1 connection pools. The body is already read upfront (line 147), so an idempotent retry would be safe for the GET/HEAD/OPTIONS verbs and acceptable for POST/PUT/PATCH/DELETE that have already serialised their body bytes.Suggested fix
Extend the retry except clause to include the keep-alive-race exceptions, retrying at least once without sleep (a fresh connection is essentially free):
Alternatively, set a short
keepalive_expiryon the sharedhttpx.AsyncClient(in_get_proxy_client) so the pool recycles connections before uvicorn's idle timeout can race with the next request. Both fixes together would be belt-and-braces.Why this matters
Open WebUI polls
/ports,/files/list, etc. on intervals from the terminal panel. Each transient 500 surfaces in the browser console and (depending on the component) can briefly blank UI state until the next polling tick succeeds. Users perceive intermittent flakiness even though the system is healthy.Reproduction
terminalsagainst the Docker backend with a configured policy.Request Counton the pooled connection climbs. At some point the upstream closes it; the next request fails withRemoteProtocolError→ 500.@Classic298 commented on GitHub (Jun 22, 2026):
@james-westbrook
@tjbck commented on GitHub (Jun 22, 2026):
Addressed.