Skip to content

File descriptor / unix-socket leak: RawClient builds a new http.Transport per call to Docker Desktop backend.sock #3629

Description

@aheritier

Summary

A long-running docker-agent run process leaks unix-domain socket file descriptors steadily. A 9.5-hour session was observed holding 1,028 open unix-domain sockets (FD numbers contiguously spanning 6→1071), climbing toward the process FD ceiling.

Root cause

pkg/desktop/raw_client.go: RawClient.client is a func() *http.Client that constructs a brand-new http.Client + bare http.Transport on every call. Each call dials Docker Desktop's backend.sock. With HTTP keep-alives enabled and no IdleConnTimeout set, the connection is parked in the throwaway transport's idle pool and pinned indefinitely by its persistConn goroutines → 1 leaked unix FD (+2 goroutines) per call.

Primary trigger — one leak per LLM request (Gateway mode)

In Docker AI Gateway mode, per-request auth-token closures call base.GatewayAuthToken on every request, then unmemoized desktop.GetToken and ClientBackend.Get.

Secondary drips include 1-minute /ping probes, unmemoized IsDockerDesktopRunning, and 5-minute GetVersion.

MCP client pooling and stdio child reaping were verified correct and are not the cause.

Impact

Long-lived sessions accumulate unix-socket FDs and goroutines without bound, risking EMFILE / “too many open files”.

Proposed fix

Build the RawClient HTTP client/transport once and reuse it, with a bounded idle pool (for example MaxIdleConns: 2, IdleConnTimeout: 90s). Optionally memoize desktop.GetToken and cache the gateway auth client per provider. Add a regression test asserting open unix-socket connections stay flat across many Get calls.

Evidence

A 48-second sampling window showed FD count flat at 1028 while mid-turn; the leak is tied to discrete LLM requests. FD breakdown: 1,028 unix sockets of 1,088 total FDs, zero established TCP; RSS was ~450MB.

Metadata

Metadata

Assignees

Labels

area/coreCore agent runtime, session managementarea/gatewayGateway, proxy, and routingkind/fixPR fixes a bug (maps to fix:). Use on PRs only.

Type

Fields

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions