[Bug] Auto-mode classifier incorrectly detects permission mode change in plan mode, causing repeated manual approval fallback

Status Open
Reported on v2.1.218
Maintainer reply None cached
Activity 7 comments · opened Jul 23, 2026

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:

  1. Start a session already in plan mode (plan mode active before the first prompt; never toggled during the session).
  2. Give a task that triggers read-only exploration (file reads, cd, git read commands, spawning Explore agents).
  3. 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.

View original on GitHub ↗

7 Comments

Unity2Blender · 1 month ago

In the Plan mode, this is causing so much frustration from the UX point.

scrothers · 1 month ago

@claude this problem is affecting everyone. Can we get this fixed please?

scrothers · 1 month ago

Dug into this further since the docs suggest useAutoModeDuringPlan should prevent it, and there's a CLAUDE_CODE_AUTO_MODE_CLASSIFIER_QUEUE env 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:

  1. 2.1.218 changed plan mode so Bash commands the static analyzer can't prove read-only get judged by the auto-mode classifier instead of always prompting.
  2. 2.1.219 added a remote Statsig gate (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, emitting MODE_CHANGED_WHILE_QUEUED_REASON ("Permission mode changed while the auto-mode classifier call was queued").
  3. There's an env-var override wired up for this (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:

function QMd(){let e=Og.CLAUDE_CODE_AUTO_MODE_CLASSIFIER_QUEUE;
  if(e!==void 0)return{value:e,src:"env"};
  return Ke("tengu_auto_mode_classifier_queue",!1)===!0?{value:!0,src:"gb"}:{value:!1,src:"default"}}

but Og (meant to expose env vars as getters) is built from a literal empty object:

efh={}, Og=rOl(efh,null)

rOl only defines a getter per key in the object it's given, so with zero keys in efh, Og.CLAUDE_CODE_AUTO_MODE_CLASSIFIER_QUEUE is always undefined — 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 neighboring CLAUDE_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.

ovelar · 1 month ago

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 plan branch is:

case "plan": return A9() && (tool.isReadOnly(parsedInput) || r2o(...));

That predicate depends only on the tool and its input — no timing component — so any tool call failing isReadOnly takes 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 the tengu_auto_mode_classifier_queue feature 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 isReadOnly check 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_ask with reason: "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.

ovelar · 1 month ago

@scrothers — independently hit the same efh={} / Og=rOl(efh,null) accessor, so that part matches on my end too (the neighbouring CLAUDE_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: false is wired up properly and short-circuits the whole path:

function KMi(){ return Pr("policySettings")?.useAutoModeDuringPlan !== false
             && Pr("flagSettings")?.useAutoModeDuringPlan  !== false
             && Pr("userSettings")?.useAutoModeDuringPlan  !== false
             && Pr("localSettings")?.useAutoModeDuringPlan !== false }
function CUo(){ return gk() && KMi() }
function zfn(e){ if(!CUo()) return null; return $N(true), Lte(e) }   // $N writes vfe.active; A9() reads it

Setting it false makes KMi() false, so CUo() is false, so $N(true) is never reached and A9() stays false — which makes Xqs("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() consults policySettings, flagSettings, userSettings and localSettingsnot projectSettings. Putting the key in a project-level .claude/settings.json fails 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.

chungshan · 1 month ago

I get the same issue. any updates?

DavidAntliff · 1 month ago

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.