You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
第一个模型报错upstream_server_error时,failover切换到第二个deepseek官方api模型,报错丢失字段:
Provider error 400: {"error":{"message":"The reasoning_text in the thinking mode must be passed back to the API.","type":"invalid_request_error","param":null,"code":"invalid_request_error"}}
Version
2.54.0
Operating system
macOS 13.5.1
Provider and model
No response
Logs or error output
Screenshots and supporting files
No response
Redacted configuration
Checks
I searched existing issues and documentation.
I removed secrets, tokens, account details, request credentials, and personal data.
이 이슈는 Codex CLI에서 DeepSeek 모델을 콤보(조합)로 묶었을 때, 첫 번째 타깃이 upstream_server_error로 실패하고 콤보 failover가 두 번째 DeepSeek 공식 API 모델로 넘어간 뒤, 그 다음 요청이 Provider error 400 — The reasoning_text in the thinking mode must be passed back to the API. 로 죽는다는 보고입니다. 작성자 환경은 2.54.0 / macOS / Codex CLI이고, 재현 칸은 비어 있지만 스크린샷과 정확한 업스트림 문구가 붙어 있습니다. 품질 봇이 재현 단계 공백으로 이슈를 자동 닫았지만(not_planned), 에러 문자열과 콤보 failover 서술은 이미 알려진 DeepSeek thinking/Responses 계열 결함과 맞춰 볼 수 있어서, 메인테이너 입장에서는 닫힌 채 방치하기보다 재오픈·보강 후 추적하는 편이 맞습니다.
현재 추적 중인 dev HEAD는 5dfea7235deb5942f9a5c657e075fed0fa388fad 이고 package.json은 2.57.0입니다(#4686으로 2.56.0 제품 동결 386303af1 이후 열린 버전). 2.56.0 promote 레인(#4694)과 OAuth 429 사다리/#4690 reauth backoff는 이 이슈의 직접 원인이 아닙니다. 이 보고의 핵심 축은 (1) 콤보가 upstream_server_error에서 의도적으로 hop 하는 정책과, (2) DeepSeek thinking/Responses가 이전 턴의 plaintext reasoning을 다시 요구하는 계약이, 타깃이 바뀐 뒤에도 깨지지 않는지입니다.
코드로 보면 콤보 실패 판정은 src/combos/failover.ts의 comboFailureDecision 입니다. 상태코드 5xx뿐 아니라 구조화 코드 upstream_server_error 도 명시적으로 "hop" 을 반환합니다. 실제 hop 루프는 src/server/responses/core-combo.ts 에서 자식 요청을 다시 만들고(concreteComboRequestBody / buildComboChildHeaders), consumeComboFailure 뒤 failureDecision === "hop" 이면 다음 타깃으로 갑니다. 즉 ‘첫 DeepSeek가 upstream_server_error → 두 번째 DeepSeek로 전환’ 자체는 버그가 아니라 현재 설계입니다. 문제는 hop 이후 두 번째 타깃으로 나가는 히스토리에 thinking 필드가 빠질 때입니다.
DeepSeek 공식 레지스트리(src/providers/registry/entries-core.ts, id deepseek)는 preserveResponsesReasoningContent: true 와 preserveReasoningContentModels: DEEPSEEK_NATIVE_THINKING_MODELS(deepseek-flash / deepseek-v4-flash)를 심어 둡니다. Responses 경로에서는 src/adapters/openai-responses/passthrough.ts 가 sanitizeReasoningInputContent(src/adapters/openai-responses/reasoning.ts)를 호출하고, preserve 플래그가 켜져 있을 때만 plaintext reasoning_text content를 비우지 않습니다. Chat 경로에서는 src/adapters/openai-chat/messages.ts 가 reasoning_content 를 되살리고, 캐시 미스 시 placeholder를 넣는 방어(#950/#1193 계열)가 있습니다. 캐시 본체는 src/responses/reasoning-replay-cache.ts 인데, 키에 provider/model/credential identity가 들어가므로 콤보 hop으로 serving identity가 바뀌면 peekReasoningForCall 이 빗나갈 수 있습니다. 같은 파일/ src/server/responses/core-replay.ts 쪽에서 identity 변경 시 _stripReasoningEncryptedContent 가 켜지면 opaque blob은 의도적으로 벗겨지지만, 이미 클라이언트 히스토리에 plaintext reasoning_text 가 없거나 이전 타깃에서 blanked 된 상태면 공식 DeepSeek는 바로 이번 400을 냅니다.
과거에 같은 업스트림 문구로 닫힌 이슈가 있습니다: #1477 / #1534 (DeepSeek V4 Flash Responses continuation에서 reasoning_text 유실 → 400), #2106 (다른 원인으로 스트림이 끊긴 뒤 reasoning replay 400). 그것들은 대체로 단일 프로바이더·도구 연속 턴 쪽이었고, 이번 #4696은 ‘콤보 failover hop 직후’라는 축이 새로 붙습니다. 지금 열린 이슈 목록에서 동일 제목/동일 재현의 중복은 보이지 않았고, #4688(DeepSeek 카탈로그 id 불일치)은 다른 축입니다. types.ts/config.ts 대분할로 무효화되는 PR 이슈도 아닙니다. 보고 버전 2.54.0과 현재 2.57.0/dev 사이에 콤보+DeepSeek reasoning 전용 수정이 동결 트리에 뚜렷이 잡히지 않으므로, ‘이미 고쳤다’고 닫기보다 현재 HEAD 기준으로 재현·회귀를 확인하는 쪽이 정직합니다.
src/combos/failover.ts · comboFailureDecision - upstream_server_error 는 hop 이 맞고, 이 이슈의 1단계(전환 자체)는 정상 경로다
src/server/responses/core-combo.ts · 자식 재디스패치 - hop 시 요청 본문/히스토리를 다음 DeepSeek 타깃으로 넘기는데, thinking 필드 보존 보장이 콤보 경계에 명시되어 있지 않다
src/adapters/openai-responses/reasoning.ts · sanitizeReasoningInputContent - preserveResponsesReasoningContent 가 꺼지거나 히스토리에 reasoning_text 가 비어 있으면 content=[] 로 비워 DeepSeek thinking 400을 유발할 수 있다
src/adapters/openai-responses/passthrough.ts · preserveRawReasoningContent / stripEncryptedContent - 타깃 identity 변경 시 opaque strip 과 plaintext keep 이 엇갈리면 hop 직후 공식 API만 400이 난다
src/responses/reasoning-replay-cache.ts · keyFor / peekReasoningForCall - 캐시 키가 provider·model·credential 에 묶여 있어 콤보 hop 후 Chat 경로 재부착이 미스날 수 있다
src/adapters/openai-chat/messages.ts · reasoning_content / placeholder - Chat 쪽은 미스 시 공백 placeholder 방어가 있으나, 보고된 에러 문구는 Responses reasoning_text 계약이라 Chat 방어만으로는 커버되지 않는다
src/providers/registry/entries-core.ts · deepseek preserveResponsesReasoningContent - 공식 deepseek 엔트리는 preserve=true 이지만, 콤보 첫 타깃이 다른 DeepSeek류(게이트웨이/커스텀)면 플래그·와이어 불일치로 히스토리가 이미 빈 content 일 수 있다
이슈 본문 Reproduction - 품질 봇이 단계 공백으로 자동 닫음; 스크린샷+에러 문구는 충분해 보이므로 재오픈·보강이 필요하다
메인테이너의 판단이 필요한 지점
자동 닫힘(not_planned)을 메인테이너가 재오픈할지, 작성자에게 콤보 타깃 목록(provider/model 순서)·어느 턴에서 hop 했는지·Responses인지 Chat인지만 추가로 받고 유지할지
수정 범위를 ‘공식 deepseek Responses만’으로 좁힐지, 콤보 hop 공통으로 ‘thinking 필수 타깃이면 reasoning_text/reasoning_content 가 비었을 때 placeholder 또는 fail-soft’ 정책을 넣을지
중복으로 닫지 말고 유효 버그로 재오픈(또는 작성자 보강 후 자동 재오픈)하세요. 다음 스텝은 (1) 콤보 타깃 두 개의 정확한 provider/model 과 와이어(openai-responses vs openai-chat) 확인, (2) 현재 dev 에서 ‘DeepSeek A upstream_server_error → DeepSeek B’ hop 직후 tool-call continuation 에 reasoning_text / reasoning_content 가 살아 있는지 회귀 테스트 추가, (3) Chat placeholder와 대칭으로 Responses 쪽에도 hop 후 빈 thinking 을 막거나, 히스토리에 thinking 이 없으면 그 타깃으로는 hop 하지 않도록 좁히는 패치입니다. 2.56.0 릴리즈 트레인과는 분리해 추적하는 것을 추천합니다.
Activity
github-actions commentedon Sep 15, 2026
Issue reopened
The report now contains the information required by the automated check. Thanks for updating it.
lidge-jun commentedon Sep 15, 2026
리뷰 · 우선순위 63 / 80
설명
이 이슈는 Codex CLI에서 DeepSeek 모델을 콤보(조합)로 묶었을 때, 첫 번째 타깃이
upstream_server_error로 실패하고 콤보 failover가 두 번째 DeepSeek 공식 API 모델로 넘어간 뒤, 그 다음 요청이 Provider error 400 —Thereasoning_textin the thinking mode must be passed back to the API.로 죽는다는 보고입니다. 작성자 환경은 2.54.0 / macOS / Codex CLI이고, 재현 칸은 비어 있지만 스크린샷과 정확한 업스트림 문구가 붙어 있습니다. 품질 봇이 재현 단계 공백으로 이슈를 자동 닫았지만(not_planned), 에러 문자열과 콤보 failover 서술은 이미 알려진 DeepSeek thinking/Responses 계열 결함과 맞춰 볼 수 있어서, 메인테이너 입장에서는 닫힌 채 방치하기보다 재오픈·보강 후 추적하는 편이 맞습니다.현재 추적 중인
devHEAD는5dfea7235deb5942f9a5c657e075fed0fa388fad이고 package.json은 2.57.0입니다(#4686으로 2.56.0 제품 동결386303af1이후 열린 버전). 2.56.0 promote 레인(#4694)과 OAuth 429 사다리/#4690 reauth backoff는 이 이슈의 직접 원인이 아닙니다. 이 보고의 핵심 축은 (1) 콤보가upstream_server_error에서 의도적으로 hop 하는 정책과, (2) DeepSeek thinking/Responses가 이전 턴의 plaintext reasoning을 다시 요구하는 계약이, 타깃이 바뀐 뒤에도 깨지지 않는지입니다.코드로 보면 콤보 실패 판정은
src/combos/failover.ts의comboFailureDecision입니다. 상태코드 5xx뿐 아니라 구조화 코드upstream_server_error도 명시적으로"hop"을 반환합니다. 실제 hop 루프는src/server/responses/core-combo.ts에서 자식 요청을 다시 만들고(concreteComboRequestBody/buildComboChildHeaders),consumeComboFailure뒤failureDecision === "hop"이면 다음 타깃으로 갑니다. 즉 ‘첫 DeepSeek가 upstream_server_error → 두 번째 DeepSeek로 전환’ 자체는 버그가 아니라 현재 설계입니다. 문제는 hop 이후 두 번째 타깃으로 나가는 히스토리에 thinking 필드가 빠질 때입니다.DeepSeek 공식 레지스트리(
src/providers/registry/entries-core.ts, iddeepseek)는preserveResponsesReasoningContent: true와preserveReasoningContentModels: DEEPSEEK_NATIVE_THINKING_MODELS(deepseek-flash/deepseek-v4-flash)를 심어 둡니다. Responses 경로에서는src/adapters/openai-responses/passthrough.ts가sanitizeReasoningInputContent(src/adapters/openai-responses/reasoning.ts)를 호출하고, preserve 플래그가 켜져 있을 때만 plaintextreasoning_textcontent를 비우지 않습니다. Chat 경로에서는src/adapters/openai-chat/messages.ts가reasoning_content를 되살리고, 캐시 미스 시 placeholder를 넣는 방어(#950/#1193 계열)가 있습니다. 캐시 본체는src/responses/reasoning-replay-cache.ts인데, 키에 provider/model/credential identity가 들어가므로 콤보 hop으로 serving identity가 바뀌면peekReasoningForCall이 빗나갈 수 있습니다. 같은 파일/src/server/responses/core-replay.ts쪽에서 identity 변경 시_stripReasoningEncryptedContent가 켜지면 opaque blob은 의도적으로 벗겨지지만, 이미 클라이언트 히스토리에 plaintextreasoning_text가 없거나 이전 타깃에서 blanked 된 상태면 공식 DeepSeek는 바로 이번 400을 냅니다.과거에 같은 업스트림 문구로 닫힌 이슈가 있습니다: #1477 / #1534 (DeepSeek V4 Flash Responses continuation에서
reasoning_text유실 → 400), #2106 (다른 원인으로 스트림이 끊긴 뒤 reasoning replay 400). 그것들은 대체로 단일 프로바이더·도구 연속 턴 쪽이었고, 이번 #4696은 ‘콤보 failover hop 직후’라는 축이 새로 붙습니다. 지금 열린 이슈 목록에서 동일 제목/동일 재현의 중복은 보이지 않았고, #4688(DeepSeek 카탈로그 id 불일치)은 다른 축입니다. types.ts/config.ts 대분할로 무효화되는 PR 이슈도 아닙니다. 보고 버전 2.54.0과 현재 2.57.0/dev사이에 콤보+DeepSeek reasoning 전용 수정이 동결 트리에 뚜렷이 잡히지 않으므로, ‘이미 고쳤다’고 닫기보다 현재 HEAD 기준으로 재현·회귀를 확인하는 쪽이 정직합니다.src/combos/failover.ts · comboFailureDecision - upstream_server_error 는 hop 이 맞고, 이 이슈의 1단계(전환 자체)는 정상 경로다
src/server/responses/core-combo.ts · 자식 재디스패치 - hop 시 요청 본문/히스토리를 다음 DeepSeek 타깃으로 넘기는데, thinking 필드 보존 보장이 콤보 경계에 명시되어 있지 않다
src/adapters/openai-responses/reasoning.ts · sanitizeReasoningInputContent - preserveResponsesReasoningContent 가 꺼지거나 히스토리에 reasoning_text 가 비어 있으면 content=[] 로 비워 DeepSeek thinking 400을 유발할 수 있다
src/adapters/openai-responses/passthrough.ts · preserveRawReasoningContent / stripEncryptedContent - 타깃 identity 변경 시 opaque strip 과 plaintext keep 이 엇갈리면 hop 직후 공식 API만 400이 난다
src/responses/reasoning-replay-cache.ts · keyFor / peekReasoningForCall - 캐시 키가 provider·model·credential 에 묶여 있어 콤보 hop 후 Chat 경로 재부착이 미스날 수 있다
src/adapters/openai-chat/messages.ts · reasoning_content / placeholder - Chat 쪽은 미스 시 공백 placeholder 방어가 있으나, 보고된 에러 문구는 Responses reasoning_text 계약이라 Chat 방어만으로는 커버되지 않는다
src/providers/registry/entries-core.ts · deepseek preserveResponsesReasoningContent - 공식 deepseek 엔트리는 preserve=true 이지만, 콤보 첫 타깃이 다른 DeepSeek류(게이트웨이/커스텀)면 플래그·와이어 불일치로 히스토리가 이미 빈 content 일 수 있다
이슈 본문 Reproduction - 품질 봇이 단계 공백으로 자동 닫음; 스크린샷+에러 문구는 충분해 보이므로 재오픈·보강이 필요하다
메인테이너의 판단이 필요한 지점
dev전용으로 둘지(릴리즈 블로커로 보이지는 않음)너의 추천
중복으로 닫지 말고 유효 버그로 재오픈(또는 작성자 보강 후 자동 재오픈)하세요. 다음 스텝은 (1) 콤보 타깃 두 개의 정확한 provider/model 과 와이어(openai-responses vs openai-chat) 확인, (2) 현재
dev에서 ‘DeepSeek A upstream_server_error → DeepSeek B’ hop 직후 tool-call continuation 에reasoning_text/reasoning_content가 살아 있는지 회귀 테스트 추가, (3) Chat placeholder와 대칭으로 Responses 쪽에도 hop 후 빈 thinking 을 막거나, 히스토리에 thinking 이 없으면 그 타깃으로는 hop 하지 않도록 좁히는 패치입니다. 2.56.0 릴리즈 트레인과는 분리해 추적하는 것을 추천합니다.이 댓글은 grok-bot이 작성했습니다
hnyyghk commentedon Sep 15, 2026
所以这个现象是bug吗,预计什么时候可以修复?
hnyyghk commentedon Sep 15, 2026
可以参考这个https://api-docs.deepseek.com/guides/thinking_mode/
Merge pull request #4769 from lidge-jun/codex/pw2-deepseek-reasoning-…
lidge-jun commentedon Sep 16, 2026
Landed via #4769 at 53455e0
fix(responses): refuse a combo failover that cannot replay mandatory …
fix(responses): refuse a combo failover that cannot replay mandatory …
Merge pull request lidge-jun#4769 from lidge-jun/codex/pw2-deepseek-r…