Skip to content

fix(codex): accept ChatGPT Edu Plus accounts - #7869

Open
Exotic209093 wants to merge 1 commit into
pingdotgg:mainfrom
Exotic209093:fix/codex-edu-plus-plan
Open

fix(codex): accept ChatGPT Edu Plus accounts#7869
Exotic209093 wants to merge 1 commit into
pingdotgg:mainfrom
Exotic209093:fix/codex-edu-plus-plan

Conversation

@Exotic209093

@Exotic209093 Exotic209093 commented Aug 22, 2026

Copy link
Copy Markdown

Codex 0.148.0 added new ChatGPT plan types (edu_plus, edu_pro). T3 Code decodes account/read responses against a pinned protocol schema whose planType union predates those plans, so every OpenAI request on an Edu account fails with "Invalid payload for method 'account/read' during 'decode-payload'".

This normalizes any unrecognized planType to "unknown" before decoding, mirroring the #[serde(other)] fallback codex <= 0.147 used. Known plans still pass through untouched, so future plans can't break auth again.

Fixes #7828

ox-alpha via opencode


Note

Medium Risk
Touches request payload decoding for account (and any nested planType) responses. The change is a conservative fallback, but a bug here could mis-classify plans or hide real decode failures.

Overview
Stops account/read from failing when Codex reports newer ChatGPT plans (e.g. edu_plus) that the pinned protocol schema does not include.

Before schema decode, decodeOptionalPayload now walks object payloads and rewrites unrecognized planType strings to "unknown", matching Codex’s #[serde(other)] fallback. Known plans are left unchanged.

Adds unit and mock-peer coverage so Edu-style plans decode instead of raising invalid-payload errors.

Reviewed by Cursor Bugbot for commit 04f3a28. Configure here.

Note

Normalize unknown account planType values to "unknown" before decoding in codex-app-server

  • Adds normalizeUnknownPlanTypes, a recursive function that walks arrays and objects and replaces any string at key planType not in the known plan set with "unknown". Primitives and non-object values pass through unchanged.
  • Updates decodeOptionalPayload to run object payloads through this normalization before Schema.decodeUnknownEffect, so unrecognized plan types decode successfully instead of failing.
  • Extends the mock peer account/read handler to emit a configurable planType via CODEX_APP_SERVER_TEST_ACCOUNT_PLAN_TYPE (default "plus"), and adds tests covering the normalization path.
  • Risk: any caller relying on schema decoding to reject payloads with unknown planType values will now receive "unknown" instead of a decode error.
📊 Macroscope summarized 04f3a28. 1 file reviewed, 1 issue evaluated, 0 issues filtered, 1 comment posted

🗂️ Filtered Issues

@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1fb876e9-71bc-48fb-81bb-b9f1a17c0137

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 22, 2026
return Object.fromEntries(
Object.entries(value).map(([key, child]) => [
key,
key === "planType" && typeof child === "string" && !KNOWN_PLAN_TYPES.has(child)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High _internal/shared.ts:49

normalizeUnknownPlanTypes changes legitimate opaque payload data such as { planType: "custom" } to { planType: "unknown" } before handlers receive it. Because decodeOptionalPayload applies this recursively to every decoded payload, fields like tool arguments, structuredContent, realtime items, and web-search results are corrupted; restrict normalization to the actual account-plan fields or methods.

🤖 Copy this AI Prompt to have your agent fix this:
In file @packages/effect-codex-app-server/src/_internal/shared.ts around line 49:

`normalizeUnknownPlanTypes` changes legitimate opaque payload data such as `{ planType: "custom" }` to `{ planType: "unknown" }` before handlers receive it. Because `decodeOptionalPayload` applies this recursively to every decoded payload, fields like tool `arguments`, `structuredContent`, realtime items, and web-search results are corrupted; restrict normalization to the actual account-plan fields or methods.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 04f3a28505

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +49 to +51
key === "planType" && typeof child === "string" && !KNOWN_PLAN_TYPES.has(child)
? "unknown"
: normalizeUnknownPlanTypes(child),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve opaque planType fields outside account payloads

When a decoded response or notification contains opaque tool data—such as MCP results or dynamic-tool arguments with an application field like planType: "premium"—this key-only recursive walk silently rewrites it to "unknown". Those values are represented by Schema.Unknown in the generated protocol and should pass through unchanged, but decodeOptionalPayload is shared by every method, so unrelated thread and tool payloads are corrupted; restrict normalization to the actual account and rate-limit plan paths.

Useful? React with 👍 / 👎.

Comment on lines +70 to +72
return Schema.decodeUnknownEffect(schema)(
typeof raw === "object" && raw !== null ? normalizeUnknownPlanTypes(raw) : raw,
).pipe(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid cloning every decoded protocol payload

Because every object-shaped call to decodeOptionalPayload takes this branch, the normalizer recursively walks and reconstructs complete thread/list, thread/read, and notification payloads even though almost none contain an account plan. Large thread snapshots therefore incur an additional full traversal and allocation pass before schema decoding, while frequent notifications create unnecessary object churn; gate normalization to plan-bearing methods or handle the fallback in the relevant plan schemas instead.

AGENTS.md reference: AGENTS.md:L15-L17

Useful? React with 👍 / 👎.

@macroscopeapp

macroscopeapp Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR applies plan-type normalization recursively to all decoded protocol payloads, but the 🟠 High finding correctly identifies that this could corrupt legitimate opaque data (tool arguments, structured content) containing a planType field. The normalization should be scoped to account-related methods only.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: OpenAI models unusable on ChatGPT Edu Plus -- account/read rejects planType: "edu_plus" (codex ≥ 0.148.0)

1 participant