Skip to content

[Bug]: Cursor discovery intermittently fails on HTTP/2 pre-header EOF #3051

Closed

Description

@terrytan95

Client or integration

OpenCodex dashboard

Area

Provider adapter

Summary

Cursor live model discovery intermittently fails when the default HTTP/2 stream ends before response headers arrive. fetchCursorUsableModels then reports error: "http" with detail: "HTTP unknown"; the catalog records a discovery failure and falls back to stale or static models, so the dashboard shows "Discovery failed" even though the same OAuth account can succeed on the next request.

This is a transient pre-response transport failure, but the current retry gate only retries results classified as timeout or transport. Completed non-2xx responses and authentication failures should remain non-retryable.

Expected behaviour: classify an HTTP/2 stream ending before response headers as a transient transport failure and use the existing bounded retry, while preserving the current handling for real HTTP status codes, auth failures, decode failures, and empty responses.

Reproduction

  1. Run OpenCodex 2.36.0 with a logged-in Cursor OAuth provider, liveModels: true, and the default HTTP/2 transport.

  2. Open the dashboard Models page or trigger a Cursor catalog refresh.

  3. During an affected attempt, observe an outer HTTP 200 with an error body equivalent to:

    {"ok":false,"error":"cursor discovery http: HTTP unknown"}

  4. Retry immediately with the same process and credentials. The request commonly succeeds and reports 204 usable models.

  5. A deterministic local HTTP/2 fixture reproduces the same classification by closing the server stream with NGHTTP2_NO_ERROR before calling respond(): the current implementation returns { ok: false, error: "http", detail: "HTTP unknown" } instead of retrying.

Version

2.36.0

Operating system

macOS 27.0

Provider and model

cursor / GetUsableModels model discovery

Logs or error output

[opencodex] Cursor model discovery for "cursor" failed [transport]: HTTP/2 session failed
[opencodex] Cursor model discovery for "cursor" failed [http]: HTTP unknown

The OAuth account was still logged in, and subsequent probes returned 204 models; no token, account identifier, or request credential is included here.

Screenshots and supporting files

No response

Redacted configuration

{
  "providers": {
    "cursor": {
      "adapter": "cursor",
      "authMode": "oauth",
      "baseUrl": "https://api2.cursor.sh",
      "liveModels": true,
      "upstreamHttpVersion": null
    }
  }
}

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. added
    account-poolOAuth, credentials, Codex pool, quota, failover, plans
    providerProvider adapters, OpenAI-compat presets, upstream API quirks
    on Aug 31, 2026
  2. changed the title [-]Cursor discovery intermittently fails on HTTP/2 pre-header EOF[/-] [+][Bug]: Cursor discovery intermittently fails on HTTP/2 pre-header EOF[/+] on Aug 31, 2026
  3. lidge-jun commented on Aug 31, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 62 / 80

    설명

    이 이슈는 Cursor OAuth + liveModels:true + 기본 HTTP/2에서 GetUsableModels discovery가 간헐적으로 실패하는 버그를 적는다. 증상은 outer HTTP 200 안에 {"ok":false,"error":"cursor discovery http: HTTP unknown"}가 나오고, 로그에는 [transport]: HTTP/2 session failed와 [http]: HTTP unknown이 같이 찍힌다. 같은 프로세스·같은 자격증명으로 바로 다시 치면 204 usable models가 돌아온다. 즉 토큰/계정 문제가 아니라, 응답 헤더 전에 스트림이 끝난 pre-response 전송 실패다.

    지금 dev HEAD 293a2b887 (2.38.0)의 src/adapters/cursor/live-models.ts를 보면 원인이 선명하다. fetchCursorUsableModelsHttp2Once는 response 이벤트에서만 status를 채운다. 헤더 없이 end가 오면 status는 0이고, 기존 분기는 error: "http", detail: "HTTP unknown"으로 끝낸다. 바깥 fetchCursorUsableModels는 RETRYABLE_DISCOVERY_ERRORS(timeout, transport)만 한 번 더 시도하므로 http로 분류되면 재시도가 없다. 카탈로그는 discovery 실패를 기록하고 stale/static으로 내려가 대시보드에 Discovery failed가 뜬다. 이슈에 적힌 NGHTTP2_NO_ERROR로 respond() 전에 스트림을 닫는 로컬 픽스처도 같은 분류를 재현한다.

    기대 동작 서술도 정확하다. pre-header EOF는 transient transport로 보고 기존 바운드 재시도를 쓰고, 완료된 HTTP 상태·auth·decode·empty는 그대로 비재시도여야 한다. 재현 환경(2.36.0, macOS, api2.cursor.sh, liveModels true, upstreamHttpVersion null)과 redacted config도 충분하다. 이미 짝 PR #3052(terry-fix/cursor-discovery-http2-retry)가 정확히 그 한 줄 재분류 + 회귀 테스트를 들고 와 있다. 현재 dev의 Cursor 열차(#2865/#2876/#2900/#2940 등)와 겹치지 않는 별도 구멍이다.

    경로/심볼 fetchCursorUsableModelsHttp2Once end 핸들러 - status===0을 http unknown으로 보내는 현재 분류가 이슈의 직접 원인이다.
    경로/심볼 RETRYABLE_DISCOVERY_ERRORS - transport로만 바꾸면 기존 1회 재시도가 살아난다. 새 재시도 정책이 필요 없다는 이슈 서술과 일치한다.
    경로/심볼 #3052 - 이미 Closes #3051로 연결되어 있다. 이슈 쪽 추가 패치는 필요 없다.
    경로/심볼 HTTP/1.1 경로 - 이슈는 기본 HTTP/2만 적는다. upstreamHttpVersion을 1.1로 핀한 사용자 보고는 아직 없다.
    재현 절차 3–5단계 - 실패→즉시 성공 패턴과 결정적 픽스처까지 있어서 메인테이너가 로컬에서 바로 검증 가능하다.

    메인테이너의 판단이 필요한 지점

    • #3052가 draft를 벗고 CI를 통과하면 이 이슈를 Closes로 닫을지(권장)
    • 2.36.0 사용자에게 cherry-pick/핫픽스가 필요한지, 아니면 다음 2.38 열차에 실을지
    • HTTP/1.1 discovery에도 같은 분류 구멍이 있는지 별도 티켓을 열지

    너의 추천

    #3052 리뷰·머지를 이 이슈의 해결 경로로 삼아라. 이슈 본문은 원인·기대·재현이 모두 맞고, 중복 이슈도 아니다. 별도 설계(needs-design)나 types/config 스플릿 무효화 대상이 아니다. #3052가 랜딩되면 Closes로 자동 종료되는지 확인하고, 안 닫히면 landed-via-maintainer로 닫으면 된다.

    이 댓글은 grok-bot이 작성했습니다

  4. lidge-jun commented on Sep 1, 2026

    @lidge-jun
    Owner

    Landed on dev via #3102 at a3656a9. Exact PR head checks were green and the landed commit was verified in the current dev history. Closing this bug as fixed.

  5. github-actions commented on Sep 1, 2026

    @github-actions
    Contributor

    Automated translation bookkeeping — detected language: English.

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

    account-poolOAuth, credentials, Codex pool, quota, failover, plansbugSomething isn't workingproviderProvider adapters, OpenAI-compat presets, upstream API quirks

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions