CLAUDE LABJP
CODE — Claude Code has moved on to v2.1.267. It was v2.1.263 yesterday, so four releases landed in the space of a single dayEFFORT — A new maxEffortLevel setting caps the effort level across every provider, Bedrock, Vertex and Foundry included. People can still choose something lowerCACHE — The largest part of this release is not a feature at all. More than a dozen fixes address cases where prompt cache reuse quietly brokeRESUME — Resuming a session or switching models with /model could rewrite the tool definitions, and the only visible symptom was a bill that crept upwardGATEWAY — v2.1.266 undoes a regression. Setups carrying CLAUDE_CODE_USE_GATEWAY were failing every request. The fix is the upgrade itself, not a config changePLUGIN — --plugin-dir now accepts a folder of plugins, and a path containing a backslash can no longer slip past the containment check on macOS or LinuxCODE — Claude Code has moved on to v2.1.267. It was v2.1.263 yesterday, so four releases landed in the space of a single dayEFFORT — A new maxEffortLevel setting caps the effort level across every provider, Bedrock, Vertex and Foundry included. People can still choose something lowerCACHE — The largest part of this release is not a feature at all. More than a dozen fixes address cases where prompt cache reuse quietly brokeRESUME — Resuming a session or switching models with /model could rewrite the tool definitions, and the only visible symptom was a bill that crept upwardGATEWAY — v2.1.266 undoes a regression. Setups carrying CLAUDE_CODE_USE_GATEWAY were failing every request. The fix is the upgrade itself, not a config changePLUGIN — --plugin-dir now accepts a folder of plugins, and a path containing a backslash can no longer slip past the containment check on macOS or Linux
Articles/Claude Code
Claude Code/2026-09-10Intermediate

When Every Request Fails With Not signed in to the Cloud gateway, Check the Version Before the Config

A Claude Code 2.1.265 regression broke every request for gateway and proxy setups. I use it as an excuse to build a small snapshot of the auth input surface, so the next time something breaks you can tell config from version in seconds.

Claude Code251Troubleshooting16Environment Variables2LLM GatewayAuthentication4

I was reading through a release diff published on September 8th when one line stopped me. Setups that run Claude Code behind a gateway or proxy had been failing every single request on the previous version.

The message they saw was Not signed in to the Cloud gateway. Nothing in the configuration had changed. It simply stopped working one morning.

If that sounds familiar, you may have settings.json open right now. That file is probably fine.

The short answer — a 2.1.265 regression, fixed in 2.1.266

The cause was a change in how CLAUDE_CODE_USE_GATEWAY is handled. It is an undocumented environment variable, which is part of why this was hard to see.

Before 2.1.265, the variable only meant something when both ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN were set. On its own it was ignored. In 2.1.265 it started forcing Cloud gateway sign-in all by itself.

So any setup that paired it with an API key, an apiKeyHelper, or custom auth headers began failing every request with Not signed in to the Cloud gateway.

Version 2.1.266, released on September 8th, restored the original behavior: on its own, the variable is ignored again. There is nothing to fix in your config. Upgrading is the whole answer. The primary source is the claude-code v2.1.266 release notes.

VersionCLAUDE_CODE_USE_GATEWAY set on its own
2.1.264 and earlierIgnored (only takes effect alongside ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN)
2.1.265Forces gateway sign-in on its own, so existing setups fail every request
2.1.266 and laterIgnored again

If that were all, this would be a short notice. What actually held my attention was not the fix. It was the place people reach for first when something breaks.

We suspect the config because three inputs converge on one point

Claude Code authentication arrives from three directions at once: environment variables, settings.json, and apiKeyHelper. On top of that, .claude/settings.json exists at both the user and project level, and shell profiles differ from machine to machine.

Which means there is a decent chance that something you do not remember setting is currently in effect. An internal onboarding doc added a line to a shared shell profile. An export from an old experiment never got cleaned up. When the variable is undocumented, as it was here, it is even less likely to be in anyone's memory.

For a while my instinct in these moments was to start editing settings.json and see what happened. That did not serve me well. I thought I was hunting for the reason it broke, and instead I was slowly dismantling the part that had been correct all along.

What deserves suspicion is not the config by itself, but the pairing of config and version. Look at only one side and you will spend the afternoon repairing the side that never moved.

A script that puts the auth input surface on one page

So I keep a twenty-line script around. It does not print values. It prints what is present.

#!/usr/bin/env bash
# authsurface.sh — put the Claude Code auth input surface on one page
set -u
 
mask() {
  local v="${1:-}"
  [ -z "$v" ] && { echo "(unset)"; return; }
  local n=${#v}
  if [ "$n" -le 8 ]; then echo "set(len=$n)"; else echo "set(len=$n, tail=${v: -4})"; fi
}
 
# Version goes first on purpose — it becomes the axis when you diff later
echo "version=$( { claude --version 2>/dev/null || echo 'claude-not-found'; } | head -1 )"
 
# Secrets: presence and length only
for k in ANTHROPIC_API_KEY ANTHROPIC_AUTH_TOKEN; do
  echo "$k=$(mask "${!k:-}")"
done
 
# Values you actually need to read
for k in ANTHROPIC_BASE_URL ANTHROPIC_CUSTOM_HEADERS CLAUDE_CODE_USE_GATEWAY \
         CLAUDE_CODE_USE_BEDROCK CLAUDE_CODE_USE_VERTEX; do
  echo "$k=${!k:-(unset)}"
done
 
# For settings files, "exists" is not the question — "what is in it" is
for f in "$HOME/.claude/settings.json" "./.claude/settings.json" "./.claude/settings.local.json"; do
  if [ -f "$f" ]; then
    helper=$(python3 -c "import json,sys;print(json.load(open(sys.argv[1])).get('apiKeyHelper','(none)'))" "$f" 2>/dev/null || echo "(parse-error)")
    force=$(python3 -c "import json,sys;print(json.load(open(sys.argv[1])).get('forceLoginMethod','(none)'))" "$f" 2>/dev/null || echo "(parse-error)")
    echo "settings:$f apiKeyHelper=$helper forceLoginMethod=$force"
  else
    echo "settings:$f (absent)"
  fi
done

On a machine sitting behind a gateway, the output looks like this.

version=2.1.260 (Claude Code)
ANTHROPIC_API_KEY=set(len=23, tail=1234)
ANTHROPIC_AUTH_TOKEN=(unset)
ANTHROPIC_BASE_URL=https://llm-gw.internal.example/v1
ANTHROPIC_CUSTOM_HEADERS=(unset)
CLAUDE_CODE_USE_GATEWAY=1
CLAUDE_CODE_USE_BEDROCK=(unset)
CLAUDE_CODE_USE_VERTEX=(unset)
settings:/home/you/.claude/settings.json (absent)
settings:./.claude/settings.json (absent)
settings:./.claude/settings.local.json (absent)

With that page in hand, this particular regression is visible at a glance. CLAUDE_CODE_USE_GATEWAY=1 is present while ANTHROPIC_AUTH_TOKEN is (unset) — the exact combination that 2.1.264 quietly ignored, still sitting there.

One note on secrets. The mask wrapper exists so you can paste this output into an issue or a team channel without thinking twice. Length plus the last four characters is enough to answer "did the key get swapped for a different one," and nothing beyond that is needed. For the full landscape of variables, the Claude Code environment variables reference covers far more ground than this script does.

Storing version and config together turns triage into seconds

I save the output with a timestamp and compare it against the previous one. The moment to run it is right after upgrading.

#!/usr/bin/env bash
# authsnap.sh — save the auth input surface and diff it against the last one
set -u
DIR="${AUTHSNAP_DIR:-$HOME/.claude-authsnap}"
mkdir -p "$DIR"
NOW="$DIR/$(date +%Y%m%d-%H%M%S).txt"
"$(dirname "$0")/authsurface.sh" > "$NOW"
 
PREV=$(ls -1 "$DIR"/*.txt 2>/dev/null | grep -v "$(basename "$NOW")" | tail -1)
[ -z "${PREV:-}" ] && { echo "(nothing to compare yet — diffs start next run)"; exit 0; }
 
if diff -u "$PREV" "$NOW" > /tmp/authsnap.diff; then
  echo "RESULT: input surface unchanged"
else
  CHANGED=$(grep -cE '^[+-][A-Za-z]' /tmp/authsnap.diff)
  VERONLY=$(grep -E '^[+-][A-Za-z]' /tmp/authsnap.diff | grep -cv '^[+-]version=')
  if [ "$VERONLY" -eq 0 ]; then
    echo "RESULT: only the version changed (config is identical)"
  else
    echo "RESULT: the config side moved too (${CHANGED} lines)"
  fi
  sed -n '4,40p' /tmp/authsnap.diff
fi

Running it twice with an upgrade in between produces this.

compare: 20260910-150742.txt -> 20260910-150744.txt
RESULT: only the version changed (config is identical)
-version=2.1.260 (Claude Code)
+version=2.1.265 (Claude Code)
 ANTHROPIC_API_KEY=set(len=23, tail=1234)
 ANTHROPIC_AUTH_TOKEN=(unset)
 ANTHROPIC_BASE_URL=https://llm-gw.internal.example/v1

One line of diff, and that one line is your evidence that you changed nothing. If ANTHROPIC_BASE_URL had moved as well, the verdict flips to the config side moved too, and so does the thing you go looking at.

The verdict is deliberately binary. When someone reads a log during an outage, the question they want answered before any of the details is whether this is their fault. Settle that first and the rest can be read calmly.

Putting version at the top of the output serves the same purpose. diff reports in line order, so a version change always surfaces as the first line you see.

The three places to look when the version was not the cause

When the verdict comes back as the config side moved too, this is the order I work through.

  1. forceLoginMethod pinned in managed settings. With "gateway" in place, a leftover API key or a claude.ai login is ignored and /login becomes mandatory. Bedrock, Vertex AI, and Foundry sessions are unaffected.
  2. What apiKeyHelper actually returns. The helper can exit cleanly and still hand back an empty string or a value with a trailing newline. Run bash -c "$(your helper)" | od -c | head and read all the way to the end.
  3. Key spelling. A single wrong character in a settings.json key is ignored without a word, which I wrote about separately in a one-letter typo in settings.json.

All three present identically: authentication, and only authentication, stops working. That symmetry is exactly why having the input surface on one page ahead of time pays for itself.

If you run unattended jobs, the related failure mode where credentials get overwritten mid-run is covered in one transient 401 replaced my long-lived token. That one may matter more to you than this one does.

For today, run authsurface.sh once on the machine you actually work from and keep the output. The diff becomes useful the moment you next upgrade. I have made a habit of spending that extra few seconds every time I bump the version.

And if your morning ends up saved by nothing more than a version bump, I'll count that as a good outcome for both of us.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $15 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Claude Code2026-09-04
The ~/.claude.json Rollback Is Fixed in v2.1.259. Putting Back What It Erased Is Still Your Job
Concurrent sessions used to silently roll back each other's ~/.claude.json changes. v2.1.259 fixed that, but nothing restores the trust settings and MCP servers you already lost. Here is how I find and rebuild them, with a small key-path diff script.
Claude Code2026-09-01
Drop the quotes on a heredoc and the prices in your log quietly change
An unquoted heredoc runs the variables and backticks inside its body. Here are the four ways my log got rewritten, how the three quoting forms compare, a safe placeholder-and-sed pattern, and a small script for auditing what you already have.
Claude Code2026-08-22
Switching to headersHelper in Claude Code broke auth for project-scoped catalogs only
Moving a private plugin catalog to headersHelper worked at user scope and failed under the project directory. The cause was credential non-inheritance. Here are two working helpers, measured execution costs, and what unattended runs need.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links