Skip to content

antigravity-ls-proxy: callRpc has no timeout — a language server that heartbeats but never answers an RPC hangs /v1/models and every chat request forever #2102

Closed

Description

@dezren39

Summary

bin/antigravity-ls-proxy.mjs's callRpc — the single method every language-server RPC goes through — calls fetch with no timeout signal. A language server that is alive enough to pass the proxy's heartbeat but wedged on real RPCs (deadlocked, stuck on its own upstream) hangs every dependent request forever: /v1/models, and every /v1/chat/completions (which blocks on GetAvailableModels before it even starts a cascade). The heartbeat in the same file pins AbortSignal.timeout(1500) (:224), and bin/sync-models.mjs's identical GetAvailableModels call pins 3000 ms — callRpc is the one unguarded path.

Evidence (main 82b019a0)

  • bin/antigravity-ls-proxy.mjs:372-383 — callRpc(method, payload) does await fetch(url, { method: 'POST', headers, body }) with no signal, no AbortSignal.timeout, no deadline of any kind; callers: GetAvailableModels (:420, via getLiveCatalog), StartCascade (:793), SendUserCascadeMessage (:806), GetCascadeTrajectorySteps (:824), GetModelResponse (:913).
  • Same file, :217-226 — checkHeartbeat uses signal: AbortSignal.timeout(1500), so a wedged-but-listening server passes health checks while its RPCs hang: ensureActive succeeds, then the request waits indefinitely.
  • The cascade poll loop (:822-843) has a nominal cap (120 attempts × 250 ms, then "Cascade execution timed out after 30 seconds") that a single hung GetCascadeTrajectorySteps callRpc defeats — the loop never advances to the next attempt.
  • getLiveCatalog (:417-430) caches for 60 s, but a hung first pull never resolves and never caches, so every /v1/models and chat request piles onto the same indefinite wait.

Probe (laptop, 2026-10-28, shipped file unmodified)

Probe dir: ~/git/fleet/probe-2026-10-28-laneB-lsrpc/ (laptop) — stub language server that answers Heartbeat with 200 and never responds to any other RPC (the test file's own env attach path, ANTIGRAVITY_LS_ADDRESS/ANTIGRAVITY_CSRF_TOKEN), shipped proxy on an alternate port:

  • Proxy starts and /health answers (heartbeat path works against the stub).
  • GET /v1/models: no response after 8001 ms (client-side abort fired; stub logged the hanging GetAvailableModels RPC).
  • POST /v1/chat/completions: no response after 8002 ms (blocked on the same hanging GetAvailableModels callRpc, before any cascade RPC).

Why it matters

This proxy fronts a language server that is a separate, crash- and deadlock-prone process. The failure mode "process alive, RPCs wedged" is exactly the one the heartbeat cannot distinguish — and it converts a backend wedge into indefinitely hung client requests with no error, no log line, and no recovery short of restarting the proxy (which doesn't unwedge the server). Every sibling call site in the fleet already bounds this wait (heartbeat 1500 ms here; sync-models 3000 ms for the same RPC; clef-proxy 10 s, #2100; design-code-proxy dispatch, #2097).

Acceptance criteria

  • callRpc carries a bounded timeout (triage pins the value; it must comfortably exceed normal GetModelResponse/cascade-step latency — a generous per-RPC bound, not a total-request deadline), and a timed-out RPC surfaces as an error the existing catch paths already handle (e.g. getLiveCatalog's last-known-good fallback engages instead of hanging).
  • A language server that heartbeats but never answers RPCs: /v1/models answers within a bounded time (live catalog or static floor), and a chat request fails with a clean error within a bounded time — never an indefinite hang.
  • The cascade poll loop's 30-second cap becomes effective: a hung poll RPC counts against it instead of defeating it.
  • Tests in bin/antigravity-ls-proxy.test.mjs style: stub LS in heartbeat-ok/RPC-hang mode → models and chat requests resolve (value or clean error) within a bounded time; slow-but-alive LS (answers after a delay under the bound) still succeeds.
  • Existing behaviours unchanged: heartbeat timeout, live-catalog 60 s cache + last-known-good, model resolution (antigravity-ls-proxy: reasoning_effort 'default'/'name' resolves to a non-enum model — MODEL_MAP metadata keys pass the family lookup #686 tests), cascade and direct-RPC chat paths against a healthy stub.

Dedup

gh issue list --search "antigravity-ls-proxy timeout callRpc" and --search "antigravity": no issue covers a missing callRpc timeout. Related but distinct: #2097 (design-code-proxy backend dispatch), #2100 (clef-proxy data-path fetch), #494 (closed, LS address parsing).

Activity

  1. developing-today commented on Oct 29, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    effort/sSmall: expected under 2 hours of work
    app/antigravity-ls-proxyPackage/app: antigravity-ls-proxy (bin/ in this repo)
    on Oct 29, 2026
  3. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator-code-b
    • Session / ID: new-issue-creator-code-b run 2026-10-29T03:57Z
    • Found via: filed this run
    • Task: Triage the callRpc missing timeout: a language server that passes the 1.5s heartbeat but never answers an RPC hangs /v1/models and every chat request indefinitely, and defeats the cascade poll loop's own 30s cap.
    • Expectation: effort/s — done when callRpc carries a bounded per-RPC timeout (triage pins the value), a heartbeat-ok/RPC-hang stub yields bounded answers/clean errors on models + chat paths, and hang/slow stub tests land in antigravity-ls-proxy.test.mjs.
    • Links: evidence in issue body; probe ~/git/fleet/probe-2026-10-28-laneB-lsrpc/ (laptop, shipped file unmodified, main 82b019a)
  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 1, 2026
  5. 11 remaining items

  6. added
    work/assignedQueue worker lifecycle state
    and removed
    status/triagedTriaged and routed (see agent note)
    on Nov 1, 2026
  7. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  8. added
    queue/needs-reviewQueue task finished and is awaiting review
    and removed
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Nov 1, 2026
  9. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

  10. added a commit that references this issue on Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/antigravity-ls-proxyPackage/app: antigravity-ls-proxy (bin/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions