Client or integration
Codex App
Provider or upstream service
OpenAI/Codex (K12)
OpenCodex version
2.24.1
Endpoint or capability
Authentication and account/thread routing
Current behaviour
The published denial classifier recognizes structured codes only at the top level or under error.code. The observed response shape is:
{"detail":{"code":"codex_workspace_access_denied","message":"..."}}
A local regression test returned denial = null before the patch. Adding an own-property check for detail.code returned denial = "workspace", and the incorrect needs-reauth state disappeared.
A fresh task bound exactly to the K12 selector completed with HTTP 200 and was routed to the K12 pool account. Switching an existing Plus-bound task to the same exact K12 selector produced four reproducible HTTP 403 responses without fallback.
Expected behaviour
K12 should continue to work in clean tasks, and workspace denials nested under own-property detail.code must be classified as workspace denials rather than credential failures.
When an existing Plus-bound thread is switched to an exact K12 selector, OpenCodex must either start clean/remove incompatible thread metadata or return a clear thread/account incompatibility. It must never mark the account needs-reauth for this case.
Minimal redacted request or reproduction
1. Reauthenticate a valid K12 account and verify the upstream plan is K12.
2. Start a fresh task explicitly bound to that K12 account and select `k12test/gpt-5.6-sol`; observe HTTP 200.
3. Start a task under Plus, then switch that existing task to the same exact K12 selector.
4. Observe reproducible HTTP 403 responses with no fallback.
5. Unit-test denial classification with `{ detail: { code: "codex_workspace_access_denied" } }`; current result is `null` instead of `workspace`.
Actual response or error
Fresh exact-K12 task: HTTP 200.
Existing Plus-bound task switched to exact K12: four reproducible HTTP 403 responses, no fallback. The nested denial envelope is:
{"detail":{"code":"codex_workspace_access_denied","message":"..."}}
OpenCodex incorrectly transitions to `needs-reauth` unless `detail.code` is handled.
Upstream documentation
No public upstream specification appears to document this private WHAM denial envelope. The concrete client requirement is established by the observed response shape, successful clean-task routing, and the reproducible cross-account/thread case.
Suggested mapping or implementation notes
Extend structured denial extraction to accept own-property detail.code, alongside the existing top-level and error.code paths. Add a regression test: an existing Plus-bound thread switched to an exact K12 selector must either shed incompatible metadata/start clean or return an explicit thread/account incompatibility, never needs-reauth.
Additional context and attachments
Follow-up to #1789. Reauthentication succeeded, credentials were valid, and the authenticated upstream check returned HTTP 200 with the K12 plan. This confirms that K12 works through OpenCodex in a clean task; the remaining failure is specific to cross-account/thread metadata.
No additional private data should be necessary. If maintainers need a diagnostic build tested, I can offer one anonymized K12 run.
Checks
Client or integration
Codex App
Provider or upstream service
OpenAI/Codex (K12)
OpenCodex version
2.24.1
Endpoint or capability
Authentication and account/thread routing
Current behaviour
The published denial classifier recognizes structured codes only at the top level or under
error.code. The observed response shape is:{"detail":{"code":"codex_workspace_access_denied","message":"..."}}A local regression test returned
denial = nullbefore the patch. Adding an own-property check fordetail.codereturneddenial = "workspace", and the incorrectneeds-reauthstate disappeared.A fresh task bound exactly to the K12 selector completed with HTTP 200 and was routed to the K12 pool account. Switching an existing Plus-bound task to the same exact K12 selector produced four reproducible HTTP 403 responses without fallback.
Expected behaviour
K12 should continue to work in clean tasks, and workspace denials nested under own-property
detail.codemust be classified as workspace denials rather than credential failures.When an existing Plus-bound thread is switched to an exact K12 selector, OpenCodex must either start clean/remove incompatible thread metadata or return a clear thread/account incompatibility. It must never mark the account
needs-reauthfor this case.Minimal redacted request or reproduction
Actual response or error
Fresh exact-K12 task: HTTP 200. Existing Plus-bound task switched to exact K12: four reproducible HTTP 403 responses, no fallback. The nested denial envelope is: {"detail":{"code":"codex_workspace_access_denied","message":"..."}} OpenCodex incorrectly transitions to `needs-reauth` unless `detail.code` is handled.Upstream documentation
No public upstream specification appears to document this private WHAM denial envelope. The concrete client requirement is established by the observed response shape, successful clean-task routing, and the reproducible cross-account/thread case.
Suggested mapping or implementation notes
Extend structured denial extraction to accept own-property
detail.code, alongside the existing top-level anderror.codepaths. Add a regression test: an existing Plus-bound thread switched to an exact K12 selector must either shed incompatible metadata/start clean or return an explicit thread/account incompatibility, neverneeds-reauth.Additional context and attachments
Follow-up to #1789. Reauthentication succeeded, credentials were valid, and the authenticated upstream check returned HTTP 200 with the K12 plan. This confirms that K12 works through OpenCodex in a clean task; the remaining failure is specific to cross-account/thread metadata.
No additional private data should be necessary. If maintainers need a diagnostic build tested, I can offer one anonymized K12 run.
Checks