MagicTools
Developer ToolsAugust 5, 20266 views4 min read

GA4 Data API Proxy Environment Timeout DEADLINE_EXCEEDED: gRPC Doesn't Recognize Uppercase HTTPS_PROXY

I. Problem Description

In a local Node.js script using the @google-analytics/data SDK to fetch GA4 reports, after waiting for a full minute, it throws:

 4 DEADLINE_EXCEEDED: Deadline exceeded after 59.999s,name resolution: 0.016s,Waiting for LB pick

The strange part is:

  • The terminal clearly has export HTTPS_PROXY=http://127.0.0.1:7897
  • Using curl with the same proxy to access Google works perfectly: curl -x http://127.0.0.1:7897 https://analyticsdata.googleapis.com returns instantly
  • The Service Account JSON key hasn't been changed and was verified effective in other scripts

Network is working, credentials are correct, proxy is running, but the SDK just can't connect.

II. Environment

Item Details
OS macOS (Darwin 23.6)
Node.js 22.18.0
SDK @google-analytics/data v4
Proxy Local Clash mixed port 127.0.0.1:7897
Network Environment Domestic, accessing Google API must go through proxy

III. Troubleshooting Process

First step: Rule out credential issues. If it were a Service Account or permission problem, Google would return 401/403, not wait 60 seconds for timeout. DEADLINE_EXCEEDED is a typical "request didn't reach the other end" – credentials suspicion eliminated.

Second step: Rule out the proxy itself. curl -x http://127.0.0.1:7897 directly accesses analyticsdata.googleapis.com and returns normally, so the proxy chain is fine.

Third step: Look closely at the error wording. The real clue is hidden in the latter part of the error:

Waiting for LB pick

"LB pick" (load balancer pick) is not a term from the HTTP world; this is gRPC channel's internal state. This means @google-analytics/data doesn't use HTTP/REST under the hood, but gRPC – the HTTPS_PROXY I set is for HTTP clients, and the gRPC stack might not read it at all.

Fourth step: Check the grpc-js source code to verify. Opening node_modules/@grpc/grpc-js/build/src/http_proxy.js, the logic of getProxyInfo() is clear:

if (process.env.grpc_proxy) {
    envVar = 'grpc_proxy';
    proxyEnv = process.env.grpc_proxy;
}
else if (process.env.https_proxy) { ... }
else if (process.env.http_proxy) { ... }
else {
    return {};   // no proxy found -> direct connection -> blocked -> 60s timeout
}

All three variables are lowercase: grpc_proxyhttps_proxyhttp_proxy, taking the first one in this priority. Environment variables in Unix-like systems are case-sensitive – my exported uppercase HTTPS_PROXY is non-existent to grpc-js.

IV. Root Cause

Three layers stacked together:

  1. @google-analytics/data uses gRPC instead of REST. It behaves completely differently from the googleapis family (GSC, Drive, etc., use REST/gaxios), so you can't just apply proxy experience from them.

  2. grpc-js only reads lowercase grpc_proxy / https_proxy / http_proxy, and uppercase HTTPS_PROXY is not in its lookup list. curl, gaxios, etc., recognize both cases, which is the direct reason for "curl works but SDK doesn't".

  3. When it can't read proxy configuration, grpc-js silently connects directly without throwing any "proxy not effective" message, and the direct connection being blocked results in a 60-second DEADLINE_EXCEEDED – the error message is miles away from the root cause.

V. Another Pitfall: Proxy Address Must Have http:// Prefix

If you’re lazy during the fix and write a bare address:

grpc_proxy=127.0.0.1:7897 node report.js

You'll get another error, and then still 60 seconds timeout:

cannot parse value of "grpc_proxy" env var

In the source code, getProxyInfo() uses new URL(proxyEnv) to parse the variable value; if parsing fails (or the scheme isn’t http:), it logs a line and returns {} – the same effect as not setting it. So the value must be a complete URL:

grpc_proxy=http://127.0.0.1:7897

VI. Fix Solution

Set both variables once (keep uppercase for REST-based tools, and lowercase specifically for gRPC):

HTTPS_PROXY=http://127.0.0.1:7897 \
grpc_proxy=http://127.0.0.1:7897 \
node scripts/ga-report.js

Verification: the request that used to hang for 60 seconds now returns data within 2 seconds.

Some trade-offs:

  • Theoretically, exporting only lowercase https_proxy would satisfy both grpc-js and most HTTP clients, but explicitly setting grpc_proxy makes the intent clearer (it has the highest priority in grpc-js) and won’t affect other traffic that shouldn’t go through the proxy.

  • It’s not recommended to write it directly into shell configuration files for global effect – domestic APIs (if your script calls other services) might be misdirected to overseas proxies and fail. It’s most stable to inject at the script level with a prefix.

  • If you run it in an npm script from package.json, remember to put the proxy variables before npm run, not inside the script content.

VII. Extension: Same Credentials, GSC Script Has Another Pitfall

After fixing GA4, I wrote a data script for Google Search Console following the same approach, but it couldn’t connect again – because the GSC API uses REST, and Node.js’s built-in fetch doesn’t read any proxy environment variables, which is the opposite pitfall from this one. That’s the content of another article: "Node.js Built-in fetch Doesn’t Use HTTPS_PROXY: The Second Pitfall for Google API Connections".

VIII. Troubleshooting Mantras

  • If the error contains terms like LB pick / channel, the other side is gRPC, don’t troubleshoot with HTTP thinking.

  • curl works but SDK doesn’t → It’s highly likely that the environment variable isn’t being read by the SDK. Check the source code to confirm which variable it reads and the case sensitivity.

  • For proxy environment variables, always write the complete URL (with http://). Bare host:port has unpredictable parsing behavior across different libraries.

Related Articles

Node.js Built-in Fetch Doesn't Use HTTPS_PROXY: The Second Pitfall When Connecting to Google API

curl works with proxy, but fetch in Node scripts times out? Node.js built-in fetch (undici) is designed not to read environment variables like HTTPS_PROXY. This article explains this behavior through the actual troubleshooting process of Google Search Console API, and provides three fix paths: google-auth-library's client.request(), undici ProxyAgent, and the experimental switch in newer Node versions.

developerAug 5, 20264 min
7

Cloudflare Wallets Explained: An Identity and a Stablecoin Wallet for AI Agents — cloudflare.pay Handles Are Live

On August 4, 2026, Cloudflare announced Cloudflare Wallets and cloudflare.pay during Agents Week: a human-readable, stable identity for AI agents plus a stablecoin wallet with owner-defined spending guardrails. This guide covers the problem it solves, how Account Wallets and Virtual Wallets split responsibilities, how x402 micropayments complete the two-sided agentic market, and the one thing you can do today — reserve your wallet handle.

cloudflareai-agent+4
ai-tutorialsAug 5, 20266 min
3

Next.js Full-Site Hydration Mismatch: The Root Cause is GTM-Loaded AdSense, Not Your Code

The Next.js site console randomly shows 'A tree hydrated but some attributes didn't match,' and the first page in cold cache is clean while subsequent pages always report it? The root cause is not in your components, but in the AdSense auto-ads loaded by GTM injecting scripts into the head before React hydration, colliding with the inline GTM script. This article explains the timing puzzle, a one-line fix, and diagnostic techniques using Playwright to capture the full error diff.

developerAug 5, 20264 min
8

GitHub Actions Fails Quickly with Connection Reset: The Cross-Border Pitfall When Overseas Runners Pull Alibaba Cloud ACR

GitHub Actions build fails two seconds after starting at load metadata, reporting failed to fetch oauth token: connection reset by peer, with the error pointing to the FROM line in the Dockerfile. Don't change the code—this is an intermittent interruption in the cross-border link from overseas runners to the Alibaba Cloud ACR authentication service. This article provides criteria, a workflow with automatic retries, and a structural solution.

developerAug 5, 20264 min
5

Published by MagicTools