[BUG] Can't use claude behind tunnel proxy

Resolved 💬 14 comments Opened Jun 18, 2025 by defi-failure Closed Aug 22, 2025

Environment

  • Platform (select one):
  • [x] Anthropic API
  • [ ] AWS Bedrock
  • [ ] Google Vertex AI
  • [ ] Other: <!-- specify -->
  • Claude CLI version: <!-- output of claude --version --> 1.0.27 (Claude Code)
  • Operating System: <!-- e.g. macOS 14.3, Windows 11, Ubuntu 22.04 --> macOS 14.6.1
  • Terminal: <!-- e.g. iTerm2, Terminal App --> Warp, Terminal(native)

Bug Description

<!-- A clear and concise description of the bug -->

❯ claude
╭──────────────────────────╮
│ ✻ Welcome to Claude Code │
╰──────────────────────────╯

 Unable to connect to Anthropic services

 Failed to connect to console.anthropic.com: ERR_BAD_REQUEST

 Please check your internet connection and network settings.

 Note: Claude Code might not be available in your country. Check supported countries at https://anthropic.com/supported-countries

<details>

<summary>this is debug output</summary>

╭──────────────────────────╮
│ ✻ Welcome to Claude Code │
╰──────────────────────────╯

  follow-redirects options {
  maxRedirects: 21,
  maxBodyLength: Infinity,
  protocol: 'https:',
  path: '/api/hello',
  method: 'GET',
  headers: [Object: null prototype] {
    Accept: 'application/json, text/plain, */*',
    'User-Agent': 'claude-cli/1.0.27 (external, cli)',
    'Accept-Encoding': 'gzip, compress, deflate, br'
  },
  agents: {
    http: undefined,
    https: bd1 {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      options: [Object],
      requests: [Object: null prototype] {},
      sockets: [Object: null prototype] {},
      freeSockets: [Object: null prototype] {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      scheduling: 'lifo',
      maxTotalSockets: Infinity,
      totalSocketCount: 0,
      proxy: URL {},
      proxyHeaders: {},
      connectOpts: [Object],
      Symbol(shapeMode): false,
      Symbol(kCapture): false,
      Symbol(AgentBaseInternalState): {}
    }
  },
  auth: undefined,
  family: undefined,
  beforeRedirect: [Function: mz9],
  beforeRedirects: { proxy: [Function: G] },
  hostname: 'api.anthropic.com',
  port: '',
  agent: bd1 {
    _events: [Object: null prototype] {
      free: [Function (anonymous)],
      newListener: [Function: maybeEnableKeylog]
    },
    _eventsCount: 2,
    _maxListeners: undefined,
    options: { path: undefined },
    requests: [Object: null prototype] {},
    sockets: [Object: null prototype] {},
    freeSockets: [Object: null prototype] {},
    keepAliveMsecs: 1000,
    keepAlive: false,
    maxSockets: Infinity,
    maxFreeSockets: 256,
    scheduling: 'lifo',
    maxTotalSockets: Infinity,
    totalSocketCount: 0,
    proxy: URL {
      href: 'http://127.0.0.1:8080/',
      origin: 'http://127.0.0.1:8080',
      protocol: 'http:',
      username: '',
      password: '',
      host: '127.0.0.1:8080',
      hostname: '127.0.0.1',
      port: '8080',
      pathname: '/',
      search: '',
      searchParams: URLSearchParams {},
      hash: ''
    },
    proxyHeaders: {},
    connectOpts: { ALPNProtocols: [Array], host: '127.0.0.1', port: 8080 },
    Symbol(shapeMode): false,
    Symbol(kCapture): false,
    Symbol(AgentBaseInternalState): {}
  },
  nativeProtocols: {
    'http:': {
      _connectionListener: [Function: connectionListener],
      METHODS: [Array],
      STATUS_CODES: [Object],
      Agent: [Function],
      ClientRequest: [Function: ClientRequest],
      IncomingMessage: [Function: IncomingMessage],
      OutgoingMessage: [Function: OutgoingMessage],
      Server: [Function: Server],
      ServerResponse: [Function: ServerResponse],
      createServer: [Function: createServer],
      validateHeaderName: [Function],
      validateHeaderValue: [Function],
      get: [Function: get],
      request: [Function: request],
      setMaxIdleHTTPParsers: [Function: setMaxIdleHTTPParsers],
      maxHeaderSize: [Getter],
      globalAgent: [Getter/Setter],
      WebSocket: [Getter],
      CloseEvent: [Getter],
      MessageEvent: [Getter]
    },
    'https:': {
      Agent: [Function: Agent],
      globalAgent: [Agent],
      Server: [Function: Server],
      createServer: [Function: createServer],
      get: [Function: get],
      request: [Function: request]
    }
  }
} +0ms
  follow-redirects options {
  maxRedirects: 21,
  maxBodyLength: Infinity,
  protocol: 'https:',
  path: '/v1/oauth/hello',
  method: 'GET',
  headers: [Object: null prototype] {
    Accept: 'application/json, text/plain, */*',
    'User-Agent': 'claude-cli/1.0.27 (external, cli)',
    'Accept-Encoding': 'gzip, compress, deflate, br'
  },
  agents: {
    http: undefined,
    https: bd1 {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      options: [Object],
      requests: [Object: null prototype] {},
      sockets: [Object: null prototype],
      freeSockets: [Object: null prototype] {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      scheduling: 'lifo',
      maxTotalSockets: Infinity,
      totalSocketCount: 0,
      proxy: URL {},
      proxyHeaders: {},
      connectOpts: [Object],
      Symbol(shapeMode): false,
      Symbol(kCapture): false,
      Symbol(AgentBaseInternalState): {}
    }
  },
  auth: undefined,
  family: undefined,
  beforeRedirect: [Function: mz9],
  beforeRedirects: { proxy: [Function: G] },
  hostname: 'console.anthropic.com',
  port: '',
  agent: bd1 {
    _events: [Object: null prototype] {
      free: [Function (anonymous)],
      newListener: [Function: maybeEnableKeylog]
    },
    _eventsCount: 2,
    _maxListeners: undefined,
    options: { path: undefined },
    requests: [Object: null prototype] {},
    sockets: [Object: null prototype] {
      'api.anthropic.com:443:::::::::::::::::::::': []
    },
    freeSockets: [Object: null prototype] {},
    keepAliveMsecs: 1000,
    keepAlive: false,
    maxSockets: Infinity,
    maxFreeSockets: 256,
    scheduling: 'lifo',
    maxTotalSockets: Infinity,
    totalSocketCount: 0,
    proxy: URL {
      href: 'http://127.0.0.1:8080/',
      origin: 'http://127.0.0.1:8080',
      protocol: 'http:',
      username: '',
      password: '',
      host: '127.0.0.1:8080',
      hostname: '127.0.0.1',
      port: '8080',
      pathname: '/',
      search: '',
      searchParams: URLSearchParams {},
      hash: ''
    },
    proxyHeaders: {},
    connectOpts: { ALPNProtocols: [Array], host: '127.0.0.1', port: 8080 },
    Symbol(shapeMode): false,
    Symbol(kCapture): false,
    Symbol(AgentBaseInternalState): {}
  },
  nativeProtocols: {
    'http:': {
      _connectionListener: [Function: connectionListener],
      METHODS: [Array],
      STATUS_CODES: [Object],
      Agent: [Function],
      ClientRequest: [Function: ClientRequest],
      IncomingMessage: [Function: IncomingMessage],
      OutgoingMessage: [Function: OutgoingMessage],
      Server: [Function: Server],
      ServerResponse: [Function: ServerResponse],
      createServer: [Function: createServer],
      validateHeaderName: [Function],
      validateHeaderValue: [Function],
      get: [Function: get],
      request: [Function: request],
      setMaxIdleHTTPParsers: [Function: setMaxIdleHTTPParsers],
      maxHeaderSize: [Getter],
      globalAgent: [Getter/Setter],
      WebSocket: [Getter],
      CloseEvent: [Getter],
      MessageEvent: [Getter]
    },
    'https:': {
      Agent: [Function: Agent],
      globalAgent: [Agent],
      Server: [Function: Server],
      createServer: [Function: createServer],
      get: [Function: get],
      request: [Function: request]
    }
  }
} +3ms
  https-proxy-agent Creating `net.Socket`: { ALPNProtocols: [ 'http/1.1' ], host: '127.0.0.1', port: 8080 } +125ms
  https-proxy-agent Creating `net.Socket`: { ALPNProtocols: [ 'http/1.1' ], host: '127.0.0.1', port: 8080 } +1ms
╭──────────────────────────╮
│ ✻ Welcome to Claude Code │
╰──────────────────────────╯

 Unable to connect to Anthropic services

 Failed to connect to console.anthropic.com: ERR_BAD_REQUEST

 Please check your internet connection and network settings.

 Note: Claude Code might not be available in your country. Check supported countries at https://anthropic.com/supported-countries

</details>

I captured the network traffic and noticed that the request to https://api.anthropic.com/api/hello succeeded, but the request to https://console.anthropic.com/v1/oauth/hello returned a 403 Forbidden error, likely triggered by Cloudflare's bot protection. See the network log below.

<details>

<summary>https://console.anthropic.com/v1/oauth/hello network log</summary>

 GET https://console.anthropic.com/v1/oauth/hello
    Accept: application/json, text/plain, */*
    User-Agent: claude-cli/1.0.27 (external, cli)
    Accept-Encoding: gzip, compress, deflate, br
    Host: console.anthropic.com
    Connection: close

 << 403 Forbidden 4.4k
    Date: Wed, 18 Jun 2025 12:27:04 GMT
    Content-Type: text/html; charset=UTF-8
    Transfer-Encoding: chunked
    Connection: close
    accept-ch: Sec-CH-UA-Bitness, Sec-CH-UA-Arch, Sec-CH-UA-Full-Version, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform-Version, Sec-CH-UA-Full-Version-List, Sec-CH-UA-Platform, Sec-CH-UA, UA-Bitness, UA-Arch, UA-Full-Version, UA-Mobile, UA-Model, UA-Platform-Version, UA-Platform, UA
    cf-mitigated: challenge
    critical-ch: Sec-CH-UA-Bitness, Sec-CH-UA-Arch, Sec-CH-UA-Full-Version, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform-Version, Sec-CH-UA-Full-Version-List, Sec-CH-UA-Platform, Sec-CH-UA, UA-Bitness, UA-Arch, UA-Full-Version, UA-Mobile, UA-Model, UA-Platform-Version, UA-Platform, UA
    cross-origin-embedder-policy: require-corp
    cross-origin-opener-policy: same-origin
    cross-origin-resource-policy: same-origin
    origin-agent-cluster: ?1
    permissions-policy: accelerometer=(),autoplay=(),browsing-topics=(),camera=(),clipboard-read=(),clipboard-write=(),geolocation=(),gyroscope=(),hid=(),interest-cohort=(),magnetometer=(),microphone=(),payment=(),publickey-credentials-get=(),screen-wake-lock=(),serial=(),sync-xhr=(),usb=()
    referrer-policy: same-origin
    server-timing: chlray;desc="******"
    x-content-type-options: nosniff
    x-frame-options: SAMEORIGIN
    Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
    Expires: Thu, 01 Jan 1970 00:00:01 GMT
    Set-Cookie: __cf_bm=*******; path=/; expires=******; domain=.console.anthropic.com; HttpOnly; Secure; SameSite=None
    Vary: Accept-Encoding
    Server: cloudflare
    CF-RAY: *******
    Content-Encoding: br
    alt-svc: h3=":443"; ma=86400

    <some html>

</details>

<details>

<summary>https://api.anthropic.com/api/hello network log</summary>

 GET https://api.anthropic.com/api/hello
    Accept: application/json, text/plain, */*
    User-Agent: claude-cli/1.0.27 (external, cli)
    Accept-Encoding: gzip, compress, deflate, br
    Host: api.anthropic.com
    Connection: close

 << 200 OK 19b
    Date: Wed, 18 Jun 2025 12:27:04 GMT
    Content-Type: application/json
    Content-Length: 19
    Connection: close
    request-id: *****
    strict-transport-security: max-age=31536000; includeSubDomains; preload
    via: 1.1 google
    cf-cache-status: DYNAMIC
    X-Robots-Tag: none
    Server: cloudflare
    CF-RAY: *******-SIN

    {
        "message": "hello"
    }

</details>

Also, I noticed that the claude client is reporting an event named tengu_preflight_check_failed to https://statsig.anthropic.com. I'm not sure what it means, but hopefully it helps you identify the issue.

<details>

<summary>event request body</summary>

{
  "events": [
    {
      "eventName": "tengu_preflight_check_failed",
      "metadata": {
        "isConnectivityError": false,
        "hasErrorMessage": true,
        "model": "claude-sonnet-4-20250514",
        "sessionId": "*******",
        "userType": "external",
        "betas": "claude-code-20250219,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14",
        "env": "{\"platform\":\"darwin\",\"nodeVersion\":\"v24.1.0\",\"terminal\":\"WarpTerminal\",\"packageManagers\":\"npm\",\"runtimes\":\"node\",\"isRunningWithBun\":false,\"isCi\":false,\"isClaubbit\":false,\"isGithubAction\":false,\"isClaudeCodeAction\":false,\"isClaudeAiAuth\":false,\"version\":\"1.0.27\"}",
        "entrypoint": "cli"
      },
      "user": {
        "customIDs": {
          "sessionId": "*******"
        },
        "userID": "********",
        "appVersion": "1.0.27",
        "custom": {
          "userType": "external"
        },
        "statsigEnvironment": {
          "tier": "production"
        }
      },
      "time": 1000
    }
  ],
  "statsigMetadata": {
    "sdkVersion": "3.12.1",
    "sdkType": "javascript-client",
    "stableID": "******",
    "sessionID": "******",
    "fallbackUrl": null
  }
}

</details>

Steps to Reproduce

  1. <!-- First step -->
  2. <!-- Second step -->
  3. <!-- And so on... -->

Expected Behavior

<!-- What you expected to happen -->

Actual Behavior

<!-- What actually happened -->

Additional Context

<!-- Add any other context about the problem here, such as screenshots, logs, etc. -->

View original on GitHub ↗

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