Repository navigation
[Bug]: a conversation carrying uploaded files should pin to its issuing account instead of being refused after rotation #4778
Description
Client or integration
Codex CLI
Area
Authentication and account pool
Summary
#4710 is now fail-closed: an account change that would orphan an uploaded file is refused with 409 account_change_file_scope instead of forwarding a reference the new account cannot read. That stops the invalid request, but it does not restore the conversation.
The refusal is a middle step, not the final shape. The real answer is to pin a conversation that carries uploaded files to its issuing account, so the rotation that causes the problem never happens.
The cost of leaving it at refusal is specific and falls entirely on pool users. A file reference stays in the conversation's history, so once rotation has moved a conversation carrying an attachment, every later turn presents the same reference and is refused the same way. The conversation is effectively blocked. The error text says this and names the two escapes (re-upload under the serving account, or start a new conversation), but both of those ask the user to absorb a routing decision they never made and cannot see.
Pool rotation is automatic and repeated, so this is not a rare shape: any conversation with an attachment is one rotation away from being blocked.
Reproduction
- Run a Codex pool with two or more accounts.
- Start a conversation and attach a file, so the request carries
file_idand the file is issued by account A. - Let routing move the conversation to account B, for example by crossing
autoSwitchThresholdor through quota-driven rotation. - Every subsequent turn is refused with
409 account_change_file_scope, because the reference remains in history.
Suggested direction
Treat "this conversation carries uploaded files" as a binding constraint in src/codex/routing.ts affinity selection, so the issuing account is retained while such references are live. conversationCarriesUploadedFiles in src/server/responses/account-change-state.ts already answers that question from the body alone and is consulted before an alternate is resolved, so the predicate exists; what is missing is the routing layer honouring it when it chooses.
Open questions for whoever picks this up: what happens when the issuing account genuinely cannot serve (exhausted, paused, needs reauth) and the conversation carries files -- pinning and availability conflict there, and refusing is probably still correct in that corner; and whether the pin should expire with the affinity record or with the file references themselves.
The refusal from #4710 should stay regardless. Pinning reduces how often it fires; it cannot be the only guard, because an account can always become unusable.
Version
2.57.0 (dev @ 3070d64)
Operating system
macOS 15.5
Logs or error output
409 account_change_file_scope (refused before dispatch; no upstream send)Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
fix(responses): refuse the uploaded-file move on the alternate-accoun…
lidge-jun commentedon Sep 16, 2026
리뷰 · 우선순위 75 / 80
이 이슈는 #4710의 다음 단계다. #4710/#4777이 ‘계정을 바꾸면 업로드 파일이 고아가 되는 이동’을 fail-closed로 거절하는 중간 단계라면, #4778은 그 거절이 필요 없도록 파일 있는 대화를 발행 계정에 핀 하라는 라우팅 계약이다. 거절만 두면 참조가 히스토리에 남아 이후 매 턴이 같은 거절로 막히고, 사용자는 재업로드나 새 대화로 라우팅 결정을 흡수해야 한다.
현재
devHEADb3035fe292의src/server/responses/account-change-state.ts에는collectFileIds(약 85행대)·canPortConversationState의uploaded-file-ids(66–67행)가 있다. 스크럽은 여전히 continuation 필드 위주라 file-only 구멍은 #4710이 말하는 그대로다. 열린 PR#4777(fix(responses): refuse an account change that would orphan an uploaded file)가conversationCarriesUploadedFiles와accountChangeFileReferenceRefusal을 추가하고 alternate-account 재시도 두 곳도 막는다. #4777 본문이 핀은 라우팅 일이라며 이 이슈(#4778)를 가리킨다.tip의
src/codex/routing.ts어피니티는 프롬프트 캐시 최적화·쿼타 헤드룸·모델 디투어 중심이다. ‘이 대화에 업로드 파일이 살아 있으면 발행 계정을 유지’하는 제약은 selection 경로에 없다. 이슈가 말하듯 술어는 #4777이 body만으로 답할 수 있게 만들고, 빠진 것은 그 답을 affinity selection이 존중하는 일이다. 풀 회전·autoSwitchThreshold가 자동이라 attachment 있는 대화는 한 번의 회전에 막힐 수 있다.거절(#4710/#4777)은 그대로 둬야 한다. 발행 계정이 소진·pause·reauth면 핀과 가용성이 충돌하고, 그때는 거절이 맞다. 핀은 거절이 얼마나 자주 터지는지만 줄인다. 핀 TTL을 affinity 기록에 묶을지 file 참조 수명에 묶을지도 열린 질문이다. cx 레인(#4764→#4765→#4777)이 착륙하기 전에 라우팅 핀 PR을 직접
dev에 올리면 재작업 위험이 크다.#4546 계정 변경 이식성·풀 비용과도 맞닿아 우선순위가 높다. types/config 스플릿과 무관하고 미리보기 배포는 없다.
경로
src/server/responses/account-change-state.tsuploaded-file-ids/collectFileIds- tip에 분류는 있고 fail-closed 거절·핀은 없다.경로 PR #4777
conversationCarriesUploadedFiles- body만으로 술어. 거절은 여기, 핀은 #4778.경로
src/codex/routing.tsaffinity selection - 업로드 파일 제약이 없어 회전이 대화를 막을 수 있다.교차 #4710 OPEN / #4777 OPEN(cx 레인 tip) - 거절 먼저, 핀은 후속.
메인테이너의 판단이 필요한 지점
너의 추천
받아라. #4777이 #4710을 닫게 랜딩한 뒤, 바로
routing.ts에서 file-carrying 대화 발행 계정 핀 PR을 이어라. 거절 가드는 제거하지 마라. cx 부모(#4764/#4765)가 먼저다.이 댓글은 grok-bot이 작성했습니다
fix(codex): apply model-denial evidence to the active pool cursor
test(codex): move account-selection preference cases into their own file
fix(codex): stop selecting accounts that cannot serve the request (#4768
lidge-jun commentedon Sep 16, 2026
Landed via #4797 at f35fbe8
fix(codex): carry uploaded-file retention through compact and keep th…
fix(responses): refuse the uploaded-file move on the alternate-accoun…
fix(codex): stop selecting accounts that cannot serve the request (li…
fix(codex): carry uploaded-file retention through compact and keep th…