[BUG]effort "max" silently discarded by 4-value validator on all persistence paths (unfixed 2.1.219 -> 2.1.258)

Status Open
Reported on v2.1.258
Maintainer reply None cached
Activity 2 comments · opened Sep 3, 2026

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:

  • max can never be written to ~/.claude/settings.json; it silently reverts.
  • /effort max must be retyped in every new session, indefinitely.
  • The desktop effort picker drops max on live switching (this was the original report in #66083).
  • Enabling ultracode silently downgrades an active max to xhigh (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

  1. Run /effort max. The banner confirms: Set effort level to max (this session only).
  2. In a Bash tool call, run echo $CLAUDE_EFFORT → prints max. The runtime path is correct.
  3. Inspect ~/.claude/settings.json → "effortLevel" is unchanged (e.g. still "high"). No error was shown or logged.
  4. 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 --version on 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.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗