[Bug] Auto-mode classifier incorrectly detects permission mode change in plan mode, causing repeated manual approval fallback
Bug Description
Bug: auto-mode classifier repeatedly falls back to manual approval in plan mode without any mode change
Version: 2.1.218
Summary: In plan mode (useAutoModeDuringPlan at its default true), read-only tool calls (cd, file reads, git status/grep) that the auto-mode classifier should silently approve instead prompt for manual approval, showing:
▎ Permission mode changed while the auto-mode classifier call was queued — falling back to manual approval under the current mode
Repro:
- Start a session already in plan mode (plan mode active before the first prompt; never toggled during the session).
- Give a task that triggers read-only exploration (file reads, cd, git read commands, spawning Explore agents).
- Observe the message above firing repeatedly, requiring manual approval for benign read-only ops.
Expected: With useAutoModeDuringPlan: true, the classifier auto-approves read-only commands without prompting.
Actual: Repeated fallback to manual approval. The user never changed permission mode, so the detected "mode change" is internal/programmatic — appears to be a race between the classifier call being queued and the
per-tool-call enable/disable of auto-mode during plan mode.
Notes: The message string is not in the docs (permission-modes, auto-mode-config, errors, changelog). It is distinct from the four documented classifier-failure cases (model unavailable / unparseable / safety-filter /
context-window-exceeded).
Environment Info
- Platform: linux
- Terminal: rxvt
- Version: 2.1.218
- Feedback ID: 8787bcac-2b42-4dfb-a33e-e4ec1fcbb3c3
Errors
[]
Might be a duplicate of #80393, #80128, #79320.
7 Comments
In the Plan mode, this is causing so much frustration from the UX point.
@claude this problem is affecting everyone. Can we get this fixed please?
Dug into this further since the docs suggest
useAutoModeDuringPlanshould prevent it, and there's aCLAUDE_CODE_AUTO_MODE_CLASSIFIER_QUEUEenv var in the gate-config table that looks like it should let you opt out of the new queued-classifier behavior entirely. It doesn't — traced it in the installed 2.1.219 binary and it's dead code.Root cause chain:
tengu_auto_mode_classifier_queue) that queues classifier calls per-agent. Its post-dequeue staleness guard has a branch that discards the classifier's verdict — even when the permission mode never actually changed — for anything not provably read-only, emittingMODE_CHANGED_WHILE_QUEUED_REASON("Permission mode changed while the auto-mode classifier call was queued").CLAUDE_CODE_AUTO_MODE_CLASSIFIER_QUEUE=false), matching the pattern other auto-mode flags use, but it's non-functional:The resolver correctly checks the env var first:
but
Og(meant to expose env vars as getters) is built from a literal empty object:rOlonly defines a getter per key in the object it's given, so with zero keys inefh,Og.CLAUDE_CODE_AUTO_MODE_CLASSIFIER_QUEUEis alwaysundefined— the env-var branch never fires, and it always falls through to the live (enabled) Statsig gate. This looks like scaffolding for a newer flag batch that never got wired to a populated schema — the neighboringCLAUDE_CODE_AUTO_MODE_GIT_STATUS*flags have the same broken accessor. Compare to the normal accessor (Z, built from real merged schema objects), where env overrides do work correctly.Net effect: there is currently no working client-side override for this specific flag — the fallback-to-manual-approval fires for effectively all non-trivially-read-only plan-mode tool calls, and setting the documented-style env var does nothing to stop it.
Reproduced on 2.1.219 (Linux, native). Reading the shipped bundle, this looks deterministic rather than a race, and there's a second effect worth separating out.
On resolve, the queued verdict is re-validated against the current mode. The
planbranch is:That predicate depends only on the tool and its input — no timing component — so any tool call failing
isReadOnlytakes the fallback on every attempt, with the mode never having changed. The reason constant (MODE_CHANGED_WHILE_QUEUED_REASON) is emitted regardless of why validation failed, which is where the misleading wording comes from.The whole re-validation block is gated on the classifier queue being enabled — env
CLAUDE_CODE_AUTO_MODE_CLASSIFIER_QUEUE, else thetengu_auto_mode_classifier_queuefeature flag, default off. It's on for my account, which may explain why this isn't universal.That gating creates a second problem. 2.1.218 says: "Changed plan mode with auto to no longer prompt for Bash commands the static analyzer can't prove read-only; the auto-mode classifier judges them instead." But with the queue on, the verdict is then discarded by the
isReadOnlycheck above — false for exactly the commands that change was written to cover. So the classifier round-trip is paid and the prompt still appears, making 2.1.218 a no-op for its stated purpose whenever the queue flag is on.tengu_auto_mode_fallback_to_askwithreason: "mode_changed_while_queued"should show how often this fires, and how much of it has no accompanying mode transition.Workaround:
useAutoModeDuringPlan: false. With the queue on, auto-mode-during-plan adds nothing in plan mode anyway — read-only tools were already auto-allowed without a classifier, and non-read-only ones get discarded — so disabling it removes the message and the latency without changing which calls prompt.Caveat: derived from reading the minified bundle, so identifier-level details may be off.
@scrothers — independently hit the same
efh={}/Og=rOl(efh,null)accessor, so that part matches on my end too (the neighbouringCLAUDE_CODE_AUTO_MODE_GIT_STATUS*resolvers share it). Two corrections worth adding, though.There is a working client-side override — it just isn't the env var.
useAutoModeDuringPlan: falseis wired up properly and short-circuits the whole path:Setting it false makes
KMi()false, soCUo()is false, so$N(true)is never reached andA9()stays false — which makesXqs("plan")false, so the classifier never engages in plan mode and the queued-verdict re-validation never runs. Applied on 2.1.219 (Linux, native) and the message is gone.One trap:
KMi()consultspolicySettings,flagSettings,userSettingsandlocalSettings— notprojectSettings. Putting the key in a project-level.claude/settings.jsonfails silently rather than erroring. It needs to go in~/.claude/settings.json.Worth being clear about what this does and doesn't buy you: it removes the misleading message and the wasted classifier round-trip, but the commands that were prompting still prompt. That's 2.1.212 working as intended (it closed a hole where plan mode ran file-modifying Bash unprompted). The bug here is that 2.1.218 promised to lift those prompts via the classifier and the queue gate silently cancels it.
Minor correction: the queued-classifier gate isn't new in 2.1.219 — this issue was filed against 2.1.218 reporting the same message, so it predates it. Worth knowing for anyone bisecting.
Caveat as before: derived from reading the minified bundle, so identifier-level details may be off.
I get the same issue. any updates?
I'm not 100% sure yet, but v2.1.220 seems to be _not_ repeatedly asking me for permission, or printing the "Permission mode changed..." warning, so may be resolved.