Skip to content

Bug: force_complete_request does not handle Running state — potential coordinator deadlock #396

@karthiknadig

Description

@karthiknadig

Summary

RefreshCoordinator::force_complete_request() only handles the Completing and Idle states. If begin_completion() panics with an "unexpected key" error, the coordinator state is restored to Running before the panic. The RefreshCompletionGuard::drop then calls force_complete_request(), which hits the _ => {} wildcard arm — leaving the coordinator permanently stuck in Running.

Root Cause

In crates/pet/src/jsonrpc.rs:

  1. Line 148-150 (begin_completion): On key mismatch, state is restored to Running(active) before panicking
  2. Line 273-278 (RefreshCompletionGuard::drop): Calls force_complete_request() during stack unwind
  3. Line 210-220 (force_complete_request): Only transitions Completing → Idle. The Running state matches _ => {} — a silent no-op.

Impact

After the panic, the coordinator is stuck in Running with no thread owning the refresh. All future refresh requests call wait_until_idle() and hang forever — deadlocking the JSONRPC server.

While the "unexpected key" panic is a defensive assertion that shouldn't fire in normal operation, if it ever fires (e.g., due to a future code change or race condition), the server becomes completely unresponsive.

Proposed Fix

Either:

  1. Have force_complete_request() also handle the Running state by transitioning to Idle + notify_all(), OR
  2. Return a Result from begin_completion() instead of panicking, allowing proper error recovery

Introduced By

PR #386 (d3a060f — fix: deduplicate concurrent refresh requests)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIssue identified by VS Code Team member as probable bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions