This guide explains how to troubleshoot and resolve network, proxy, and certificate errors (SELF_SIGNED_CERT_IN_CHAIN, UNABLE_TO_VERIFY_LEAF_SIGNATURE, UNABLE_TO_GET_ISSUER_CERT_LOCALLY, npm error code E400, 400 Bad Request, 403 Forbidden) during npm run setup in the io.Connect Desktop v10 Seed Project.
npm run setup executes in two distinct stages that fail for different reasons and require separate network/TLS handling:
- Stage 1 (Component Download): The
@interopio/iocd-clidownloads the platform binaries from GitHub releases using Node.js’s built-infetch. Node.js does not read OS proxy/PAC settings automatically. - Stage 2 (Dependency Installation): The CLI spawns child processes to run
npm installinside each application underapps/. npm has its own proxy and SSL validation behavior.
Quick Diagnostic Guide
| What you see | Stage | Likely cause | Go to |
|---|---|---|---|
SELF_SIGNED_CERT_IN_CHAIN, UNABLE_TO_VERIFY_LEAF_SIGNATURE or UNABLE_TO_GET_ISSUER_CERT_LOCALLY during component download |
Stage 1 | Node.js does not trust the corporate proxy’s re-signed CA certificate | Step 2: Configure Proxy and CA Trust |
TypeError: fetch failed and no proxy mentioned in the CLI log |
Stage 1 | Proxy environment variables are not set, or the CLI is outdated (< 0.0.54) |
Step 1 and Step 2 |
SSL/certificate errors during npm install, after Node is configured |
Stage 2 | npm needs the CA/proxy environment inherited correctly, or temporary SSL relaxation | Step 3: Configure npm SSL Settings |
npm error code E400 / 400 Bad Request on @interopio/* packages |
Stage 2 | Corporate proxy mangles URL-encoded slash (%2f) or registry mirror does not proxy the scope |
Steps 4 and 5 |
403 Forbidden mentioning rate limits |
Stage 1 | Shared corporate egress IP exceeded GitHub’s unauthenticated limit | Extra cases: GitHub Rate Limits |
| Execution stops or appears silent for minutes | Any | Component download retries or captured npm install output |
Extra cases: Log Files and Diagnostics |
| No external GitHub access | Stage 1 | Organization blocks direct access to GitHub releases | Extra cases: Air-Gapped and Offline Environments |
Which of the three certificate codes you get depends on whether the proxy sends an intermediate; all three mean the same thing here.
Applies to
- Product: io.Connect Desktop v10 Seed Project (
@interopio/iocd-cli). - CLI boundary:
@interopio/iocd-cli@0.0.54is the minimum version that reads proxy environment variables. Earlier versions attempt direct connections because those variables are not read by the CLI. - Node.js: v22.0.0 or later, the CLI’s stated minimum.
--use-system-caneeds v22.15.0 or later, which added it for every platform at once; on the 23.x line the equivalent is 23.9.0. - npm: v9.x or later, the CLI’s stated minimum. Node 22 ships npm 10.
- Corporate CA certificate: PEM-encoded
.pemor.crtfile provided by your internal IT/Security team. - Verified against:
@interopio/iocd-cli1.0.1, 1.0.3 and 1.1.0 on Node 24.18 and npm 11.16 against an intercepting proxy with a private CA.
Resolution Steps
Steps 1 and 2 are the whole fix on an ordinary corporate network. Run Step 6 to confirm, and use Steps 3 to 5 only if it still fails.
Step 1: Verify and Update the CLI Version
Proxy support was added in @interopio/iocd-cli@0.0.54. Earlier versions, including 0.0.52 and 0.0.53, ignore proxy environment variables and attempt direct connections.
Check your installed version and update if necessary:
npx iocd --version
npm update @interopio/iocd-cli
Step 2: Configure Proxy and CA Trust (Fixes Stage 1)
Because Node’s built-in fetch ignores system PAC and OS proxy settings, explicitly export the proxy endpoints and configure CA trust.
macOS / Linux (~/.zshrc or ~/.bashrc):
# 1. Define proxy endpoints
export HTTP_PROXY="http://proxy.corp.example:8080"
export HTTPS_PROXY="http://proxy.corp.example:8080"
export NO_PROXY="localhost,127.0.0.1,.corp.example"
# 2. Establish CA trust (Choose Option A or Option B)
# Option A: Explicit corporate CA file in PEM format (recommended)
export NODE_EXTRA_CA_CERTS="/path/to/corporate-ca.pem"
# Option B: OS certificate store (Node 22.15.0+)
export NODE_OPTIONS="--use-system-ca $NODE_OPTIONS"
Windows (PowerShell):
$env:HTTP_PROXY="http://proxy.corp.example:8080"
$env:HTTPS_PROXY="http://proxy.corp.example:8080"
$env:NO_PROXY="localhost,127.0.0.1,.corp.example"
# Option A: Explicit CA file (recommended)
$env:NODE_EXTRA_CA_CERTS="C:\path\to\corporate-ca.pem"
# Option B: OS certificate store
$env:NODE_OPTIONS="--use-system-ca $env:NODE_OPTIONS"
Windows (Command Prompt / persistent environment):
set HTTP_PROXY=http://proxy.corp.example:8080
set HTTPS_PROXY=http://proxy.corp.example:8080
set NO_PROXY=localhost,127.0.0.1,.corp.example
set NODE_EXTRA_CA_CERTS=C:\path\to\corporate-ca.pem
REM Persist for future sessions
setx HTTP_PROXY "http://proxy.corp.example:8080"
setx HTTPS_PROXY "http://proxy.corp.example:8080"
setx NO_PROXY "localhost,127.0.0.1,.corp.example"
setx NODE_EXTRA_CA_CERTS "C:\path\to\corporate-ca.pem"
Why Option A is recommended. Option B reads the machine’s own certificate store, so it only helps if your corporate CA has already been rolled out there. When it has not, the run fails in exactly the same way as doing nothing at all, with the same certificate error and no indication that the flag was ignored, which makes a missing CA easy to misread as a proxy problem.
Note on
.crtconversions: If your IT team provided a DER-encoded certificate, convert it with OpenSSL:openssl x509 -inform der -in corporate-ca.crt -out corporate-ca.pem
Step 3: Configure npm SSL Settings (Fixes Stage 2)
When the CLI runs npm install inside apps/*, the child process inherits HTTP_PROXY, HTTPS_PROXY, NO_PROXY, and NODE_EXTRA_CA_CERTS. In most cases, the trust configured in Step 2 is sufficient for both stages.
Do not use npm config set cafile as the default fix. Setting cafile replaces npm’s built-in root trust store instead of adding to it, which can break SSL validation for standard public packages. Prefer NODE_EXTRA_CA_CERTS, which adds the corporate CA to Node’s default roots.
If dependency installs still fail with certificate errors, and you need a temporary last-resort fallback:
npm config set strict-ssl false
Revert the setting once proper root certificates are in place:
npm config set strict-ssl true
This is temporary in intent only.
npm config setwrites to your user.npmrc, so the setting stays in force for every project on the machine until you revert it, and while it is off anything between you and the registry can hand you a package you did not ask for.
Step 4: Verify Registry Configuration
Ensure npm points to the public npm registry or your internal mirror:
npm config get registry
To point npm to your internal registry mirror:
npm config set registry "https://registry.corp.example/npm/"
Step 5: Resolve 400 Bad Request on Scoped Packages
If installation fails specifically on @interopio/* packages with:
npm error code E400
npm error 400 Bad Request - GET https://registry.npmjs.org/@interopio%2fcomponents-react
This is not a certificate error. The @interopio packages are published publicly and a missing one returns 404, so a 400 means the request arrived malformed. Two causes are worth separating:
- Proxy URL mangling (
%2f): Some corporate proxies decode or corrupt the URL-encoded slash used in scoped package requests. - Mirror scope configuration: If using an internal registry mirror such as Artifactory or Nexus, verify that the
@interopioscope is proxied through to the public npm registry rather than served from an internal allowlist.
Test from inside the failing app folder (e.g. apps/launchpad):
npm view @interopio/components-react version
npm view react version
If unscoped react succeeds but @interopio/* fails with 400, route through an internal mirror or report the %2f handling issue to your network team.
Step 6: Re-run Setup and Verify
npm run setup
npm run dev
Extra Cases to Check
GitHub Rate Limits (403 Forbidden)
Behind a corporate proxy, multiple developers share the same egress IP address. Export a standard GitHub personal access token:
export GITHUB_TOKEN="your_token_here"
Log Files and Diagnostics
Check the Log file: path printed near the top of the CLI console output:
- macOS / Linux:
$TMPDIR/@interopio-iocd-cli/cli-<timestamp>.log - Windows:
%TEMP%\@interopio-iocd-cli\cli-<timestamp>.log
Look for:
Proxy initialized— confirms proxy variables were detected.No proxy configured in environment variables— confirms variables were not detected.
Silence is not a hang. The component download makes ten attempts with exponential backoff capped at 30 seconds, so a hard certificate failure takes about two and a half minutes to report. The per-app npm install then runs with its output captured rather than streamed, so a blocked install shows nothing until it fails, which on a large app is several minutes more.
Air-Gapped and Offline Environments (Local Mirror)
Download components on a connected machine:
npx @interopio/iocd-cli@latest components download ./components-mirror \
--components "iocd@10.3.0;demos@1.3.0;devTools@2.0.0"
Update config/iocd.cli.config.json in your offline project:
{
"components": {
"store": {
"local": {
"path": "./components-mirror"
}
}
}
}
Remove any github store definition. The CLI evaluates stores in precedence order github, then local, then s3, so a local block left beside a github one has no effect.
Network Requirements (Allowlist for IT/Security)
api.github.com— component release metadatagithub.comandrelease-assets.githubusercontent.com— binary downloadsregistry.npmjs.org— dependency installations and CLI update checks*.ingest.us.sentry.io— error telemetry (or setSENTRY_ENABLED=false)
Important: Build-Time vs. Runtime Configuration
The environment variables configured here (HTTP_PROXY, HTTPS_PROXY, NO_PROXY, NODE_EXTRA_CA_CERTS, NODE_OPTIONS) apply to setup/build tooling.
io.Connect Desktop deletes HTTP_PROXY and HTTPS_PROXY from its environment at startup and takes its proxy settings from the top-level proxy block in system.json.