Skip to content

bug(agents): dead sessions with a surviving socket file are advertised as live peers #1443

Description

@daniel2010001

Before submitting

  • I searched open and closed issues and did not find a report of this problem.
  • I reviewed this report and removed credentials, tokens, private paths, hostnames, and other sensitive data.

Problem

orchestrator_list advertises sessions that are no longer alive. With exactly 3 pi processes running (verified with ps), it returned 4 peers.

SessionPresenceRegistry.advertises() decides whether a record is announced with lstat alone (lib/agents-session-transport.ts:207-216): if the endpoint path exists, is a socket, and is owned by the same user, the record is advertised. Nothing ever connects to it, so a session terminated without cleanup keeps being announced for as long as its socket file survives, in the observed profile for days.

The tool's own text says reachability is unknown, but a caller has no way to separate a live peer from a corpse, and the practical reading of the list is "4 sessions are live". That is what happened here: an agent read the list, concluded there were 4 peer sessions, and recorded it as fact.

Impact: peers that do not exist appear as coordination partners, messages to them fail, and the real session count is hidden. The leaked record also consumes discovery budget, which is the separate failure reported in #1422; that report assumes endpoints are missing, so this surviving-endpoint case is not covered there.

Steps to reproduce

  1. On Linux, in one agent profile, start session A. It publishes a presence record and binds its endpoint (SessionPresenceRegistry.record() then publish() in lib/agents-session-transport.ts).
  2. Terminate A abnormally, for example kill -9. Node unlinks a UNIX socket path on a graceful server.close() but leaves it on abnormal termination (measured with a minimal script: the path exists after listen(), is gone after close(), and survives SIGKILL). registry.removeOwn() never runs, so both the record and the endpoint file leak together.
  3. In session B, call orchestrator_list. A is advertised.
  4. orchestrator_send_message to A fails with Error: session message was not accepted. The failed connect then makes B delete A's record (registry.removeOwn(record) applied to the peer's file, lib/agents-session-transport.ts:659-664), so A stops being advertised while its .sock file stays behind permanently.

Observed before the failed sends: 3 live pi processes, 4 advertised peers, and the 3 extras carrying .sock files dated 2026-09-21 and 2026-09-23 (days earlier), with no listener in ss -lx and no /proc/<pid>/fd reference in any running process.

Expected and actual behavior

Expected: an announced peer should be reachable, or the announcement should distinguish "cannot be confirmed" from "reachable". A bounded connect attempt during discovery would demote an endpoint with no listener, and reclamation should not depend on some session happening to message the corpse. The leaked endpoint file should be reclaimed too, since nothing removes it once the owner terminates abnormally.

Actual: liveness is inferred from the existence of the socket file, so any abnormally terminated session stays advertised indefinitely. Reclamation happens only as a side effect of a failed send, and the endpoint file is never reclaimed at all.

gentle-pi version

3.7.0

Pi version

0.87.1

Operating system

Linux

Relevant logs or error output (optional)

Advertised sessions (reachability is unknown):
- <session-a>   # live
- <session-b>   # live
- <session-c>   # leaked endpoint, dated 2026-09-23
- <session-d>   # leaked endpoint, dated 2026-09-21

$ ss -lx | grep <runtime-tmp>/<profile-hash>
(no listener for <session-c> or <session-d>)

$ ls -l <runtime-tmp>/<profile-hash>
srw------- 2026-09-23 12:01 <session-c>.sock
srw------- 2026-09-21 20:24 <session-d>.sock

Error: session message was not accepted.   # for the 3 leaked peers
Message <id> from <session-b> to <session-a> accepted for delivery; it is not a delivery or read receipt.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions