Repository navigation
CLI HTTP client ignores NO_PROXY, so emulators can’t reach each other behind a proxy #11249
Description
[REQUIRED] Environment info
firebase-tools: 15.33.0 (also reproduced on 15.32.1)
Platform: Ubuntu 24.04.5 LTS (x86_64), Node.js 24.21.0
[REQUIRED] Test case
When HTTPS_PROXY is set, the CLI's HTTP client (lib/apiv2.js) sends every request through new undici.ProxyAgent({ uri: proxyURI }) and never checks NO_PROXY / no_proxy. Requests between emulators on 127.0.0.1 therefore go to the proxy too. The Functions emulator then can't register Firestore triggers with the Firestore emulator, and emulators:start / emulators:exec fail.
This affects anyone running the emulators behind a corporate or sandbox proxy, even with NO_PROXY=localhost,127.0.0.1. #4637 and #4386 describe similar symptoms on older versions.
Minimal project:
firebase.json
{
"functions": [{ "source": "functions" }],
"emulators": {
"firestore": { "port": 8080 },
"functions": { "port": 5001 },
"ui": { "enabled": false },
"singleProjectMode": true
}
}functions/package.json
{
"name": "functions",
"main": "index.js",
"engines": { "node": "24" },
"dependencies": {
"firebase-admin": "^14.4.0",
"firebase-functions": "^7.0.0"
}
}functions/index.js
const { onDocumentUpdated } = require('firebase-functions/firestore')
exports.onUserUpdated = onDocumentUpdated('users/{userId}', (event) => {
console.log('updated', event.params.userId)
})[REQUIRED] Steps to reproduce
- Create the files above and run
npm installinfunctions/. - Point the proxy variables at any proxy that can't reach localhost. A port with nothing listening is enough to reproduce:
export HTTPS_PROXY=http://127.0.0.1:9 export NO_PROXY=localhost,127.0.0.1
- Run:
firebase emulators:exec --debug --project demo-repro --only firestore,functions "echo SCRIPT RAN"
[REQUIRED] Expected behavior
Hosts listed in NO_PROXY are connected to directly, as in other Node and CLI tools. The Functions emulator registers the trigger with the local Firestore emulator, and the script runs:
✔ functions[us-central1-onUserUpdated]: firestore function initialized.
i Running script: echo SCRIPT RAN
SCRIPT RAN
✔ Script exited successfully (code 0)
[REQUIRED] Actual behavior
The request to the local Firestore emulator is sent to the proxy, so trigger registration fails:
>>> [apiv2][query] POST http://127.0.0.1:8080/emulator/v1/projects/demo-repro/eventarcTrigger?eventarcTriggerId=us-central1-onUserUpdated-0 [none]
*** [apiv2] error from fetch(http://127.0.0.1:8080/emulator/v1/projects/demo-repro/eventarcTrigger?eventarcTriggerId=us-central1-onUserUpdated-0, {"headers":{},"method":"POST","dispatcher":{...}}): Error: connect ECONNREFUSED 127.0.0.1:9
⚠ Error adding firestore function: FirebaseError: Failed to make request to http://127.0.0.1:8080/emulator/v1/projects/demo-repro/eventarcTrigger?eventarcTriggerId=us-central1-onUserUpdated-0
Error: Failed to make request to http://127.0.0.1:8080/emulator/v1/projects/demo-repro/eventarcTrigger?eventarcTriggerId=us-central1-onUserUpdated-0
ECONNREFUSED 127.0.0.1:9 is the proxy address, not the emulator. Behind a real proxy that rejects localhost, the proxy's error page comes back instead, and the emulator fails with Unable to parse JSON: SyntaxError: Unexpected token 'r', "request bl"... is not valid JSON.
Suggested fix: in lib/apiv2.js (src/apiv2.ts), use undici's EnvHttpProxyAgent, which applies NO_PROXY, with the same proxy URL:
fetchOptions.dispatcher = new undici.EnvHttpProxyAgent({ httpProxy: proxyURI, httpsProxy: proxyURI });With only this change, the same repro passes (output under "Expected behavior"). We've used it as a local patch, and our full emulator-based E2E suite passes behind a proxy. undici 6 prints an "EnvHttpProxyAgent is experimental" warning. Happy to open a PR if that approach works for you.
Activity