Skip to content

Daemon refuses new callers once 256 transports pile up from callers that are gone #468

Open

Description

@vitalijssilins

What happens

On a long-lived daemon, every call that needs a new keep-alive transport eventually fails with:

Transport capacity reached; drain unused transports with daemon stop.

Callers whose transport already exists keep working, but any new caller identity is refused. mcporter daemon status lists 256 transports, almost all of them for callers that are long gone. Only a daemon restart clears it.

Why

  1. Transport identity includes the caller's resolved environment. This is documented in docs/daemon.md, and I'm not proposing to change it. In practice, though, every coding-agent session carries its own session variables (for example CLAUDE_CODE_SESSION_ID), so each session creates its own transport per keep-alive server.
  2. Nothing removes an entry from the broker's entries map except close(). Idle retirement sets state = 'idle' and keeps the entry. Keep-alive servers without idleTimeoutMs are never retired, and an entry whose connect failed keeps its slot unless that same identity calls again.
  3. invoke refuses at entries.size >= 256, so entries left behind by callers that are gone use up the capacity permanently.

With about 11 keep-alive servers per session, the daemon refuses new sessions during roughly the 24th session since its last restart. On my machine daemon status showed 256 transports, all connected, the newest last used two days before the outage. daemon restart cleared it, but only until the same build-up happened again.

Repro (compiled CLI, private daemon)

Run one keep-alive HTTP server, then make 260 mcporter call invocations, each with a different CALLER_SESSION_ID in its environment. On main (2874448), callers 1–256 succeed and callers 257–260 fail with transport_limit. The script is linked from the PR.

Expected

Transports nobody is using should not hold capacity forever. At the limit, the broker could retire the least recently used transport that has no queued or active call. It would refuse only when no transport can be safely reclaimed.

Activity

  1. added
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    P1Urgent regression or broken agent/channel workflow affecting real users now.
    clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.
    clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.
    clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.
    impact:otherThis issue has meaningful maintainer-visible impact outside the owned taxonomy.
    issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.
    and removed
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    on Oct 26, 2026
  2. clawsweeper commented on Oct 26, 2026

    @clawsweeper
    Contributor

    Codex review: this still needs some work.

    Summary
    This issue remains source-proven on current main, and its open fixing PR has an explicit collaborator hold pending a session-retention decision.

    Reproducibility: Current source proves rejection of identity 257 because caller release and idle retirement do not free transport entries, corroborated by the contributor's inspected CLI screenshot; no tests or live reproduction ran during this read-only review.

    Root-cause cluster
    Relationship: canonical
    Canonical: #468
    Summary: This issue owns the retained-entry capacity failure addressed by the open fixing PR; searches found no separate report superseding it.

    Members:

    Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

    Maintainer decision needed

    • Question: May capacity pressure retire a quiet retained MCP session before its configured idle deadline, including when no deadline is configured?
    • Recommendation: Approve bounded pressure eviction: Accept session resets at capacity, document that additional retirement trigger, and retain the proposed protections for active or queued work, uncertain outcomes, Chrome owners, and failed retirements.
    • Why: Existing documentation preserves shared sessions across caller exits, and the collaborator explicitly left this policy choice unresolved in the linked PR.

    Next step
    Resolve the retained-session eviction policy in #469 before landing its capacity repair.

    Review details

    Best possible solution:

    Land an explicitly approved capacity-reclamation policy that preserves environment isolation, active work, uncertain outcomes, Chrome ownership, and verified retirement.

    Do we have a high-confidence way to reproduce the issue?

    Current source proves rejection of identity 257 because caller release and idle retirement do not free transport entries, corroborated by the contributor's inspected CLI screenshot; no tests or live reproduction ran during this read-only review.

    Is this the best way to solve the issue?

    The linked PR addresses slot accumulation through existing serialized retirement, but its connected-session eviction policy requires the explicit decision already requested by the collaborator.

    AGENTS.md: found and applied where relevant.

    Remaining risk / open question:

    • The broker cannot infer that a quiet caller is gone; pressure eviction can discard a live caller's retained MCP session before its configured idle deadline or when no deadline exists.

    Codex review notes: model internal, reasoning medium; reviewed against 8ba0ef967805.

    Label changes

    Label changes:

    No label changes.

    Label justifications:

    • P1: Accumulated transport identities block new agent sessions on a long-lived daemon until an operator drains or restarts it.
    • impact:other: Permanent transport-slot exhaustion prevents new connections while existing callers continue working.
    Evidence reviewed

    What I checked:

    • Current default branch verified: GitHub identifies main as the default branch, and its SHA matches the clean review checkout. (8ba0ef967805)
    • Capacity exhaustion persists: New connection identities are rejected when entries.size reaches 256; existing identities bypass that rejection. (src/daemon/broker.ts:172, 8ba0ef967805)
    • Ordinary lifecycle never frees transport entries: View release and expiry remove only views, idle retirement retains transport entries, and only broker close clears the transport map. (src/daemon/broker.ts:402, 8ba0ef967805)
    • Environment differences create distinct identities: Effective definitions incorporate inherited environment values, and connectionIdentity hashes the resulting environment. (src/daemon/connection-identity.ts:136, 8ba0ef967805)
    • Retention is an established contract: Documentation preserves transports after caller exit and view release; integration tests verify retained children across fresh callers and configured idle retirement. (docs/daemon.md:11, 8ba0ef967805)
    • Open fixing PR owns the repair: fix(daemon): reclaim unused transports at the broker limit #469 remains open and unmerged, explicitly closes this issue, and proposes serialized capacity reclamation. (6419e72fc692)
    How this review workflow works
    • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
    • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
    • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
    • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
    • Maintainers can also comment @clawsweeper review to request a fresh review only.
    • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge; those execution lanes are retired.
    • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

    Reviewed October 27, 2026, 10:43 PM ET / October 28, 2026, 02:43 UTC.

  3. added
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    and removed
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    on Oct 26, 2026
  4. 50 remaining items

  5. added
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    and removed
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    on Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Urgent regression or broken agent/channel workflow affecting real users now.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:otherThis issue has meaningful maintainer-visible impact outside the owned taxonomy.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions