Description
Outbound HTTPS requests made via axios fail inside a NemoClaw sandbox with ERR_BAD_RESPONSE: stream has been aborted. The OpenShell L7 proxy logs HTTP:UNKNOWN [INFO] DENIED UNKNOWN.
What happened: Any axios.get() or axios.post() to an external HTTPS endpoint fails. The L7 proxy closes the connection. This affects any OpenClaw plugin, skill, or tool that uses axios for outbound HTTP calls.
What I expected: axios HTTPS requests should work the same as https.request() from the same sandbox — which succeeds.
Root cause: axios has its own proxy handling that reads HTTP_PROXY/HTTPS_PROXY from the environment. Simultaneously, NODE_USE_ENV_PROXY=1 (baked into the NemoClaw container image) intercepts all http.request() / https.request() calls at the Node.js 22 engine level. When both are active, the request gets double-processed — axios configures it for HTTP forward proxy, then Node.js re-processes it through its own proxy logic. The result is a malformed request with the proxy port leaked into the destination URL:
https://clawhub.ai:3128/ ← :3128 is the proxy port, should be :443
The L7 proxy cannot parse this and rejects it as HTTP:UNKNOWN DENIED UNKNOWN.
Key finding: Node.js core https.request() works correctly through the proxy. The bug is specifically the interaction between axios and NODE_USE_ENV_PROXY.
What works vs what fails:
HTTP client | Status | Why
-- | -- | --
https.request() (Node.js core) | PASS | NODE_USE_ENV_PROXY handles CONNECT tunnel correctly alone
curl | PASS | Own CONNECT tunnel implementation
jwks-rsa | PASS | Uses https.request() internally
@azure/msal-node | PASS | Has its own HTTP client
axios (default) | FAIL | Double proxy: axios + NODE_USE_ENV_PROXY conflict
axios (proxy:false) | PASS | Axios skips proxy, NODE_USE_ENV_PROXY handles correctly
fetch() (undici) | FAIL | Similar double proxy conflict
Proof that disabling axios proxy fixes it:
# FAILS — axios default (double proxy conflict)
node -e "require('/usr/local/lib/node_modules/openclaw/node_modules/axios').get(
'https://clawhub.ai',
{timeout:10000, headers:{'User-Agent':'test'}}
).then(r => console.log('OK', r.status)).catch(e => console.log(e.code, e.message))"
# → ERR_BAD_RESPONSE stream has been aborted
# WORKS — axios with proxy:false (NODE_USE_ENV_PROXY handles it alone)
node -e "require('/usr/local/lib/node_modules/openclaw/node_modules/axios').get(
'https://clawhub.ai',
{timeout:10000, proxy:false, headers:{'User-Agent':'test'}}
).then(r => console.log('OK', r.status)).catch(e => console.log(e.code, e.message))"
# → OK 200
Suggested fix: Since NODE_USE_ENV_PROXY=1 correctly handles HTTPS proxy via CONNECT tunnel, axios's own proxy handling is redundant and conflicting. Either:
- Set
axios.defaults.proxy = false in the openclaw build (the bundled dist, not node_modules) - Or remove
NODE_USE_ENV_PROXY=1 from the Dockerfile and use a proxy preload that doesn't conflict with axios
Workaround: We run a proxy translator on 127.0.0.1:3129 that intercepts the malformed requests and converts them to proper CONNECT tunnels.
Reproduction Steps
Deploy NemoClaw and run nemoclaw onboard
Enter the sandbox:
openshell sandbox connect my-assistant
Confirm environment:
echo $HTTPS_PROXY $NODE_USE_ENV_PROXY
Run the diagnostic:
node -e "
const https = require('https');
const axios = require('/usr/local/lib/node_modules/openclaw/node_modules/axios');
const TARGET = 'https://clawhub.ai';
const UA = {headers:{'User-Agent':'nemoclaw-repro'}};
// Test 1: Node.js core https.request — should PASS
https.get(TARGET, UA, r => {
console.log('Test 1 https.request():', r.statusCode >= 200 && r.statusCode < 400 ? 'PASS' : 'FAIL', 'HTTP', r.statusCode);
r.resume();
// Test 2: axios default — should FAIL
axios.get(TARGET, {timeout:10000, ...UA})
.then(r => console.log('Test 2 axios (default):', 'PASS', 'HTTP', r.status))
.catch(e => {
console.log('Test 2 axios (default):', 'FAIL', e.code, e.message);
// Test 3: axios proxy:false — should PASS
axios.get(TARGET, {timeout:10000, proxy:false, ...UA})
.then(r => console.log('Test 3 axios (proxy:false):', 'PASS', 'HTTP', r.status))
.catch(e => console.log('Test 3 axios (proxy:false):', e.response ? 'PASS HTTP '+e.response.status : 'FAIL '+e.code));
});
}).on('error', e => console.log('Test 1 https.request():', 'FAIL', e.code));
"
Expected output (bug present):
Test 1 https.request(): PASS HTTP 200
Test 2 axios (default): FAIL ERR_BAD_RESPONSE stream has been aborted
Test 3 axios (proxy:false): PASS HTTP 200
Environment
- OS: Ubuntu 22.04 (EC2 t3.large, ca-central-1)
- Node.js: v22.22.1 (ships with NemoClaw sandbox image)
- Docker: Docker Engine (via NemoClaw bootstrap)
- NemoClaw: latest (git clone, commit d74a122 / 2026.4.2)
- OpenShell: v0.0.26 (pinned — NemoClaw rejects 0.0.27+)
- OpenClaw: 2026.4.2
- axios: 1.12.0 (from @microsoft/teams.apps dependency, also bundled in openclaw dist/)
nemoclaw-debug.tar.gz
Debug Output
Logs
ubuntu@ip-10-194-6-227:~$ nemoclaw my-assistant
✓ Connecting to sandbox 'my-assistant'
Inside the sandbox, run `openclaw tui` to start chatting with the agent.
Type `exit` (or Ctrl-D) to return to the host shell.
sandbox@my-assistant:~$ node -e "
const https = require('https');
const axios = require('/usr/local/lib/node_modules/openclaw/node_modules/axios');
const TARGET = 'https://clawhub.ai';
const UA = {headers:{'User-Agent':'nemoclaw-repro'}};
// Test 1: Node.js core https.request — should PASS
https.get(TARGET, UA, r => {
console.log('Test 1 https.request():', r.statusCode >= 200 && r.statusCode < 400 ? 'PASS' : 'FAIL', 'HTTP', r.statusCode);
r.resume();
// Test 2: axios default — should FAIL
axios.get(TARGET, {timeout:10000, ...UA})
.then(r => console.log('Test 2 axios (default):', 'PASS', 'HTTP', r.status))
.catch(e => {
console.log('Test 2 axios (default):', 'FAIL', e.code, e.message);
// Test 3: axios proxy:false — should PASS
axios.get(TARGET, {timeout:10000, proxy:false, ...UA})
.then(r => console.log('Test 3 axios (proxy:false):', 'PASS', 'HTTP', r.status))
.catch(e => console.log('Test 3 axios (proxy:false):', e.response ? 'PASS HTTP '+e.response.status : 'FAIL '+e.code));
});
}).on('error', e => console.log('Test 1 https.request():', 'FAIL', e.code));
"
(node:4396) [UNDICI-EHPA] Warning: EnvHttpProxyAgent is experimental, expect them to change at any time.
(Use `node --trace-warnings ...` to show where the warning was created)
Test 1 https.request(): PASS HTTP 200
Test 2 axios (default): FAIL ERR_BAD_RESPONSE stream has been aborted
Test 3 axios (proxy:false): PASS HTTP 200
sandbox@my-assistant:~$ exit
exit
ubuntu@ip-10-194-6-227:~$ openshell logs | tail -5
→ Using sandbox 'my-assistant' (last used)
[1776710692.914] [sandbox] [OCSF ] [ocsf] NET:OTHER [MED]
[1776710692.914] [sandbox] [OCSF ] [ocsf] NET:OPEN [INFO] ALLOWED /usr/local/bin/node(4396) -> clawhub.ai:443 [policy:clawhub engine:opa]
[1776710692.926] [sandbox] [OCSF ] [ocsf] HTTP:GET [INFO] ALLOWED GET http://clawhub.ai/ [policy:clawhub]
[1776710693.061] [sandbox] [OCSF ] [ocsf] HTTP:UNKNOWN [INFO] DENIED UNKNOWN
[1776710693.066] [sandbox] [OCSF ] [ocsf] HTTP:GET [INFO] ALLOWED GET http://clawhub.ai/ [policy:clawhub]
Checklist
Description
Outbound HTTPS requests made via
axiosfail inside a NemoClaw sandbox withERR_BAD_RESPONSE: stream has been aborted. The OpenShell L7 proxy logsHTTP:UNKNOWN [INFO] DENIED UNKNOWN.What happened: Any
axios.get()oraxios.post()to an external HTTPS endpoint fails. The L7 proxy closes the connection. This affects any OpenClaw plugin, skill, or tool that usesaxiosfor outbound HTTP calls.What I expected:
axiosHTTPS requests should work the same ashttps.request()from the same sandbox — which succeeds.Root cause:
axioshas its own proxy handling that readsHTTP_PROXY/HTTPS_PROXYfrom the environment. Simultaneously,NODE_USE_ENV_PROXY=1(baked into the NemoClaw container image) intercepts allhttp.request()/https.request()calls at the Node.js 22 engine level. When both are active, the request gets double-processed — axios configures it for HTTP forward proxy, then Node.js re-processes it through its own proxy logic. The result is a malformed request with the proxy port leaked into the destination URL:The L7 proxy cannot parse this and rejects it as
HTTP:UNKNOWN DENIED UNKNOWN.Key finding: Node.js core
https.request()works correctly through the proxy. The bug is specifically the interaction betweenaxiosandNODE_USE_ENV_PROXY.What works vs what fails:
HTTP client | Status | Why -- | -- | -- https.request() (Node.js core) | PASS | NODE_USE_ENV_PROXY handles CONNECT tunnel correctly alone curl | PASS | Own CONNECT tunnel implementation jwks-rsa | PASS | Uses https.request() internally @azure/msal-node | PASS | Has its own HTTP client axios (default) | FAIL | Double proxy: axios + NODE_USE_ENV_PROXY conflict axios (proxy:false) | PASS | Axios skips proxy, NODE_USE_ENV_PROXY handles correctly fetch() (undici) | FAIL | Similar double proxy conflictProof that disabling axios proxy fixes it:
Suggested fix: Since
NODE_USE_ENV_PROXY=1correctly handles HTTPS proxy via CONNECT tunnel, axios's own proxy handling is redundant and conflicting. Either:axios.defaults.proxy = falsein the openclaw build (the bundled dist, not node_modules)NODE_USE_ENV_PROXY=1from the Dockerfile and use a proxy preload that doesn't conflict with axiosWorkaround: We run a proxy translator on
127.0.0.1:3129that intercepts the malformed requests and converts them to proper CONNECT tunnels.Reproduction Steps
Deploy NemoClaw and run nemoclaw onboard
Enter the sandbox:
openshell sandbox connect my-assistant
Confirm environment:
echo $HTTPS_PROXY $NODE_USE_ENV_PROXY
http://10.200.0.1:3128 1
Run the diagnostic:
node -e "
const https = require('https');
const axios = require('/usr/local/lib/node_modules/openclaw/node_modules/axios');
const TARGET = 'https://clawhub.ai';
const UA = {headers:{'User-Agent':'nemoclaw-repro'}};
// Test 1: Node.js core https.request — should PASS
https.get(TARGET, UA, r => {
console.log('Test 1 https.request():', r.statusCode >= 200 && r.statusCode < 400 ? 'PASS' : 'FAIL', 'HTTP', r.statusCode);
r.resume();
// Test 2: axios default — should FAIL
axios.get(TARGET, {timeout:10000, ...UA})
.then(r => console.log('Test 2 axios (default):', 'PASS', 'HTTP', r.status))
.catch(e => {
console.log('Test 2 axios (default):', 'FAIL', e.code, e.message);
}).on('error', e => console.log('Test 1 https.request():', 'FAIL', e.code));
"
Expected output (bug present):
Test 1 https.request(): PASS HTTP 200
Test 2 axios (default): FAIL ERR_BAD_RESPONSE stream has been aborted
Test 3 axios (proxy:false): PASS HTTP 200
Environment
nemoclaw-debug.tar.gz
Debug Output
Logs
Checklist