# Troubleshoot npm run setup SELF\_SIGNED\_CERT\_IN\_CHAIN, npm SSL, and E400 Errors in io.Connect Desktop v10

**URL:** https://community.interop.io/t/troubleshoot-npm-run-setup-self-signed-cert-in-chain-npm-ssl-and-e400-errors-in-io-connect-desktop-v10/709
**Category:** io.Connect Desktop
**Tags:** iocd-10
**Created:** [September 23, 2026, 12:59pm UTC](https://community.interop.io/t/troubleshoot-npm-run-setup-self-signed-cert-in-chain-npm-ssl-and-e400-errors-in-io-connect-desktop-v10/709 "2026-09-23T12:59:32Z")
**Posts on this page:** 1
**Page:** 1

<div class="post-metadata">

### Author: ![BShopov](https://avatars.discourse-cdn.com/v4/letter/b/c5a1d2/32.png) [@BShopov](https://community.interop.io/u/BShopov)
#### Post date: [September 23, 2026, 12:59pm UTC](https://community.interop.io/t/troubleshoot-npm-run-setup-self-signed-cert-in-chain-npm-ssl-and-e400-errors-in-io-connect-desktop-v10/709/1 "2026-09-23T12:59:32Z")

</div>

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-cli` downloads the platform binaries from GitHub releases using Node.js’s built-in `fetch`. Node.js does not read OS proxy/PAC settings automatically.
- **Stage 2 (Dependency Installation):** The CLI spawns child processes to run `npm install` inside each application under `apps/`. 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.54` is 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-ca` needs 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 `.pem` or `.crt` file provided by your internal IT/Security team.
- **Verified against:** `@interopio/iocd-cli` 1.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:

```auto
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`):**

```auto
# 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):**

```auto
$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):**

```auto
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** `.crt` conversions: If your IT team provided a DER-encoded certificate, convert it with OpenSSL:
> 
> ```auto
> 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:

```auto
npm config set strict-ssl false

```

Revert the setting once proper root certificates are in place:

```auto
npm config set strict-ssl true

```

> This is temporary in intent only. `npm config set` writes 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:

```auto
npm config get registry

```

To point npm to your internal registry mirror:

```auto
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:

```auto
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 `@interopio` scope 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`):

```auto
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

```auto
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:

```auto
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:

```auto
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:

```auto
{
  "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 metadata
- `github.com` and `release-assets.githubusercontent.com` — binary downloads
- `registry.npmjs.org` — dependency installations and CLI update checks
- `*.ingest.us.sentry.io` — error telemetry (or set `SENTRY_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`.

* * *

## Related Documentation

- [io.Connect Desktop – Seed Project Development Guide](https://docs.interop.io/desktop/developers/seed-project/index.html#development)
- [io.Connect Desktop – System Configuration](https://docs.interop.io/desktop/developers/configuration/system/index.html)
