[BUG]effort "max" silently discarded by 4-value validator on all persistence paths (unfixed 2.1.219 -> 2.1.258)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
max is a first-class effort level at runtime — /effort max works and correctly sets CLAUDE_EFFORT=max for the session — but every code path that persists or re-resolves the effort level runs the value through a validator that accepts only low | medium | high | xhigh.
max fails that check, and because the failure mode is .catch(void 0) / a bare return, it is discarded silently: no error, no warning, no log line — and the UI still shows a success banner for a setting that was never written.
Consequences:
maxcan never be written to~/.claude/settings.json; it silently reverts./effort maxmust be retyped in every new session, indefinitely.- The desktop effort picker drops
maxon live switching (this was the original report in #66083). - Enabling
ultracodesilently downgrades an activemaxtoxhigh(same resolver — see Additional Information).
This has been unfixed across four published engine builds spanning a month. In the newest build it is worse: the new per-model effort setting was introduced using a copy of the same 4-value schema, so the defect now exists in two places instead of one.
What Should Happen?
max should be persisted like every other effort level.
If max is intentionally session-only, then it should be rejected loudly instead of swallowed, and the /effort banner should say that the setting will not persist — rather than showing "Set effort level to max" for a write that silently did not happen.
Error Messages/Logs
# There is no error message. That is the bug.
$ /effort max
Set effort level to max (this session only): Maximum capability with deepest reasoning...
$ echo $CLAUDE_EFFORT
max # runtime path: correct
$ grep effortLevel ~/.claude/settings.json
"effortLevel": "high", # persisted path: silently unchanged, nothing logged
Steps to Reproduce
- Run
/effort max. The banner confirms:Set effort level to max (this session only). - In a Bash tool call, run
echo $CLAUDE_EFFORT→ printsmax. The runtime path is correct. - Inspect
~/.claude/settings.json→"effortLevel"is unchanged (e.g. still"high"). No error was shown or logged. - Start a new session → effort is back to the old value.
Root cause (static analysis of the shipped claude.exe, engine 2.1.258):
The canonical list has five values (two independent definitions in the bundle):
wRo = ["low","medium","high","xhigh","max"]
wy = ["low","medium","high","xhigh","max"]
But the persisted-settings schemas have four, with a silent-swallow catch. In 2.1.258 there are now TWO such schemas — the pre-existing global one, and a new per-model one:
effortLevel: ee(["low","medium","high","xhigh"]).optional().catch(void 0)
.describe("Persisted effort level for supported models.") // global
effortLevel: ee(["low","medium","high","xhigh"]).optional().catch(void 0)
.describe("Persisted effort level for this model.") // NEW in 2.1.258
and a normalizer returns undefined for anything outside those same four:
function X6(e){ if(e==="low"||e==="medium"||e==="high"||e==="xhigh") return e; return }
X6 gates the persistence and re-resolution paths, including the effort resolver:
if (n !== void 0) return n;
if (e.settings.ultracode === true) return "xhigh";
return X6(e.settings.effortLevel);
The session/runtime path, by contrast, does NOT gate — which is exactly why /effort max appears to work:
if (e.effortLevel !== void 0) n.CLAUDE_EFFORT = e.effortLevel;
So max is valid in motion and invalid at rest, and the disagreement is resolved by silently discarding the user's choice.
I also searched the binary for any five-branch comparison including max (e==="xhigh"||e==="max"). There is none — the four-value chain is the only shape present.
Claude Model
Opus
Is this a regression?
No, this never worked
Last Working Version
_No response_
Claude Code Version
2.1.258 (bundled with Claude Desktop 1.44121.4.0 for Windows)
Platform
Other
Operating System
Windows
Terminal/Shell
Other
Additional Information
Affected versions
| Engine | Date | Validator symbol | 4-value schema |
|---------|------------|------------------|----------------|
| 2.1.219 | 2026-08-02 | v.enum, QVe | yes (x1) |
| 2.1.229 | 2026-08-17 | Mr, Prt | yes (x1) |
| 2.1.233 | npm latest, checked 2026-08-17 | Mr | yes (x1) |
| 2.1.258 | 2026-09-03 | ee, X6 | yes (x2) |
Only minifier symbol names differ across these builds. The four-element array and the .catch(void 0) are byte-identical in all four. Between 2.1.233 and 2.1.258 the defect was not fixed but propagated — the new per-model effort setting reuses the same four-value schema.
Related: ultracode downgrades max
Same resolver, so I am reporting it here rather than as a separate issue:
N = { ultracode: "xhigh" }
...
if (e.settings.ultracode === true) return "xhigh";
A user running at max who enables ultracode is moved down to xhigh, with no indication. The two settings are mutually exclusive in effect but are presented to the user as independent.
Suggested fix
Add "max" to both settings-schema enums and to the normalizer so the at-rest validators match the canonical five-value list. Better: derive all of them from the single canonical array instead of repeating the literal — repeating it is what allowed the copy-paste into the new per-model setting.
Re: #66083
#66083 reported the desktop-picker symptom and was closed by the stale bot ("Closing for now — inactive for too long") with stateReason: COMPLETED, which reads as "fixed" in the API and in search results. It was not fixed. Filing fresh with root-cause evidence.
One part of that older report has since been fixed: /effort is now available in desktop app sessions. The validator issue is not.
Notes on my setup
- This is the Claude Desktop app on Windows, not a terminal — hence "Other" for Terminal/Shell.
- I selected "Other" for API platform because I route through an Anthropic-API-compatible endpoint. It is irrelevant to this report: the defect is client-side string validation in the shipped binary, verifiable by static analysis with no network access at all.
claude --versionon my PATH reports 2.1.143, but that is a separate npm installation. The desktop app uses its own bundled engine, 2.1.258 — that is the version this report is about.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗