Repository navigation
[Bug]: Cursor discovery intermittently fails on HTTP/2 pre-header EOF #3051
Description
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
-
Run OpenCodex 2.36.0 with a logged-in Cursor OAuth provider, liveModels: true, and the default HTTP/2 transport.
-
Open the dashboard Models page or trigger a Cursor catalog refresh.
-
During an affected attempt, observe an outer HTTP 200 with an error body equivalent to:
{"ok":false,"error":"cursor discovery http: HTTP unknown"}
-
Retry immediately with the same process and credentials. The request commonly succeeds and reports 204 usable models.
-
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
[-]Cursor discovery intermittently fails on HTTP/2 pre-header EOF[/-][+][Bug]: Cursor discovery intermittently fails on HTTP/2 pre-header EOF[/+]lidge-jun commentedon Aug 31, 2026
리뷰 · 우선순위 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 전송 실패다.지금
devHEAD293a2b887(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 리뷰·머지를 이 이슈의 해결 경로로 삼아라. 이슈 본문은 원인·기대·재현이 모두 맞고, 중복 이슈도 아니다. 별도 설계(needs-design)나 types/config 스플릿 무효화 대상이 아니다. #3052가 랜딩되면 Closes로 자동 종료되는지 확인하고, 안 닫히면 landed-via-maintainer로 닫으면 된다.
이 댓글은 grok-bot이 작성했습니다
lidge-jun commentedon Sep 1, 2026
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.
github-actions commentedon Sep 1, 2026
Automated translation bookkeeping — detected language: English.