Sessions become unrevivable: a stale `inuse.<pid>.lock` from a crashed host is never reclaimed on open
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- Shell
- Estrellas
- 11.2k
- Forks
- 1.9k
- Merge medio
- 14 h 16 min
- PR fusionados (30 d)
- 6
Descripción
Describe the bug
Several saved sessions became impossible to reopen ("crashed out / unrevivable"). On investigation the session data was not corrupt — the append-only events.jsonl replayed cleanly and the engine logged a successful resume. The sessions were blocked by runtime/lifecycle issues, not data loss.
The primary cause is stale lock handling. Each live session writes ~/.copilot/session-state/<id>/inuse.<pid>.lock. When the owning copilot --server process exits uncleanly (crash, force-quit, OS kill), the lock file is left behind. On the next open, the session is treated as in-use / unrevivable instead of checking whether that PID is still alive.
Scanning one local store, 14 of 184 sessions (~8%) carried a fault signature; 8 held an inuse.<pid>.lock whose PID was dead. Deleting the stale lock made each session openable again, and the app then spawned a fresh host and resumed normally — confirming the data was fine and only the lock blocked recovery.
Three related lifecycle defects compound the impact (details under Additional context):
- Orphaned engine host after a failed UI attach — the engine resumes but no session host registers, leaving a live server holding the lock (which then becomes defect #1 on the next attempt).
- MCP OAuth timeouts block session readiness — resume stalls ~5 minutes on
OAuth callback timeoutbefore the session is interactive, so users abort. - Unbounded
events.jsonlmakes replay hang on large/old sessions (appears to overlap #4251).
Affected version
1.0.83 (copilot --server --stdio --no-auto-update)
Steps to reproduce the behavior
Primary defect (stale lock not reclaimed):
- Open a session, then hard-kill its
copilot --serverprocess to simulate a crash / force-quit (kill -9 <pid>). - Confirm
~/.copilot/session-state/<id>/inuse.<pid>.lockremains, now pointing at a dead PID. - Try to reopen the session → it does not revive.
rmthe stale lock file → the session reopens and resumes cleanly (a fresh host is spawned andevents.jsonlreplays without error).
Expected behavior
On open, if the lock's PID is dead or a zombie, the app should reclaim the session automatically rather than treating it as in-use. A liveness check combined with a PID start-time comparison avoids the classic PID-reuse race. Recoverable work should never be gated behind a leftover lock file that only manual filesystem surgery can clear.
Additional context
- OS: macOS · shell: zsh
Defect 2 — orphaned engine host after a failed UI attach. Engine log from a single resume: the host never registers, yet the engine reports the session resumed, so the process lingers as an orphan holding the lock:
[WARNING] [rust:copilot_runtime::session::pending_request_flow] pending-request event was not delivered to the session host
{"error":"GenericFailure, no session host is registered for session <id>"}
...
[INFO] Resumed session: <id> (logged repeatedly)
Suggested fix: tie the engine host's lifetime to successful UI host registration; if registration fails/times out, tear the host down and release the lock.
Defect 3 — MCP OAuth timeouts block resume (~5 min). With several MCP servers configured, resume stalls until interactive OAuth flows time out. MCP init begins at 20:27, first hard failures at 20:32:
[ERROR] [rust:mcp_engine::session_authorizer] OAuth login failed after returning its authorization URL
{"server_name":"...","error":"OAuth callback timeout"}
During that window the session looks hung and users abort — observed as sessions whose only recent events were resume → abort (user_initiated) → shutdown, twice in a row. Suggested fix: make MCP init lazy / non-blocking; never gate session interactivity on MCP OAuth.
Defect 4 — unbounded events.jsonl. The append-only log grows without bound; worst local session reached 38.6 MB / ~13k events with 42 compaction cycles (173 re-injected system.message events ≈ 10.7 MB). Reopening replays the whole log, so large sessions hang on open even though nothing is corrupt. This looks like the same root cause as #4251; noting here for linkage. Suggested fix: snapshot-and-truncate the event log at compaction so replay cost stays bounded.
Possibly related: #4020 (session falsely "already in use by another client"), #4098 (truncated/concatenated events on resume), #4138 (resume compaction hangs), #4251 (large-session resume OOM/hang).
All four are addressable without changing the on-disk event format. Defects 1–2 turn recoverable work into apparent data loss; 3–4 make large/older sessions feel dead on open.
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Línea de trabajo
Empieza rastreando el manejo de session-open para ~/.copilot/session-state//inuse..lock y el ciclo de vida de copilot --server. Reproduce el caso de una terminación forzada y, después, inspecciona el runtime de sesión de Rust en torno a la recuperación del lock y el registro del host; el defecto principal está resuelto cuando un PID muerto o zombi ya no bloquea la reapertura y la sesión se reanuda sin eliminar manualmente el lock. Las cuestiones de OAuth y events.jsonl deben tratarse como un alcance separado.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- rust
- Área
- backend, cli
- Tipo de issue
- Error
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Estado de actividad
- Activo
- Claridad
- Bastante claro
- Aptitud para principiantes
- 45/100