Interactive-only 401 "OAuth access token has expired" with valid setup-token on Team org with channelsEnabled — print mode works; DISABLE_NONESSENTIAL_TRAFFIC fixes it

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

Summary

On a Claude Team-plan org account authenticated via a claude setup-token long-lived OAuth token (CLAUDE_CODE_OAUTH_TOKEN, sk-ant-oat01-…), every interactive-mode turn fails with a 401 (API Error: 401 Invalid authentication credentials on fresh sessions, Please run /login · API Error: 401 OAuth access token has expired. Re-authenticate to continue. on longer-running ones) — while **print mode (claude -p) with the identical token, config dir, binary, and model always succeeds**, including >200k-token requests on [1m] models and --resume <the-failing-conversation> --fork-session.

Setting CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 fully fixes interactive mode — which strongly suggests the failure originates in the auxiliary startup/feature-flag traffic (bootstrap / GrowthBook / channels), not in the messages request itself, and then surfaces as a misleading "token expired / re-login" banner on the turn.

Environment

  • Claude Code 2.1.218 (native install), macOS (Darwin 25.5.0)
  • Auth: subscription OAuth via CLAUDE_CODE_OAUTH_TOKEN from claude setup-token (Team-plan org; account role "user")
  • The org pushes remote managed settings (/status shows "Enterprise managed settings (remote)") with remote-settings.json = {"channelsEnabled": true}
  • Personal accounts (Pro/Max) on the same machine with their own CLAUDE_CONFIG_DIR + own sk-ant-oat01 env token: interactive works fine (their remote-settings.json is {})

Discrimination matrix (all with the same token, verified byte-identical via env inspection)

| Invocation | Result |
|---|---|
| claude -p "…" tiny prompt (haiku/opus/opus[1m]) | ✅ |
| claude -p with ~230k-token prompt on claude-opus-4-8[1m] | ✅ |
| claude -p --resume <failing-conversation> --fork-session (196k-token history, its real cwd) | ✅ |
| hermetic env -i replication of the interactive env, print mode | ✅ |
| interactive TUI, fresh session, tiny prompt | ❌ 401 within ~2–12s of the turn |
| interactive TUI + CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 | ✅ turn completes |
| interactive TUI, personal (non-org) account, same machine | ✅ |

Timeline note: interactive sessions on the org account worked for the first ~5h after the setup-token was minted, then began failing ~18h in (overnight) and never recovered; the token itself still validates fine in print mode days-of-hours later.

Debug-log evidence (interactive boot, --debug-file)

[ERROR] [Bootstrap] fetchBootstrapData failed: Error: connect ECONNRESET 160.79.104.10:443
[DEBUG] [Claude in Chrome] Disabled: OAuth token has no scope accepted by /api/oauth/validate
        (needs user:profile, user:office, or user:ccr_inference; env-var and setup-token
        sessions default to user:inference only)

One failing turn also surfaced API Error: 401 The socket connection was closed unexpectedly. For more information, pass 'verbose: true' in the second argument to fetch() — mixed in with the "token expired" banners, pointing at connection-level failures in the auxiliary fetch path rather than a genuinely expired credential.

Suspected mechanism (synthesis — related issues)

  • The fetchBootstrapData ECONNRESET signature matches #62327 (parallel startup fetches racing a freshly-constructed mTLS agent).
  • Interactive-vs-print 401 asymmetry with a valid OAuth token was previously reported in #25229.
  • CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC disabling GrowthBook flag evaluation (and with it channel registration, tengu_harbor) is documented in #58383 and #45918 — consistent with the flag "fixing" this by preventing the failing fetch from ever firing.
  • setup-token tokens carry only user:inference (docs: they "can't establish Remote Control sessions or fetch claude.ai connectors"; see also #22450). With the org remotely enabling channels (channelsEnabled: true), the interactive client appears to attempt channel/connector-gated auxiliary calls that this token can never satisfy — and the resulting failure is surfaced as a 401 on the user's turn, telling them to /login although their credential is valid.

Expected behavior

  1. A failure in nonessential/auxiliary traffic (bootstrap, GrowthBook, channels registration) should never fail the user's turn or render a "Please run /login · OAuth access token has expired" banner when the inference credential is valid.
  2. When running with a scope-limited CLAUDE_CODE_OAUTH_TOKEN (user:inference only), scope-gated features (channels/connectors) should be skipped gracefully — even when org-managed settings enable them — instead of poisoning turn auth.
  3. The error message should distinguish "auxiliary feature X could not authenticate (missing scope)" from "your token is expired".

Workaround

CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 (e.g. via the config dir's settings.json env block) restores interactive mode completely — at the documented-plus-undocumented cost of telemetry, error reports, GrowthBook-gated features, and the 1h prompt-cache TTL (#45381), per the coupling catalogued in #69528.

View original on GitHub ↗