Skip to content
ecdsa.com
Node.js tls / https / fetchNode.js crypto

Error message

self-signed certificate in certificate chain

Also printed as

  • code: 'SELF_SIGNED_CERT_IN_CHAIN'
  • SELF_SIGNED_CERT_IN_CHAIN

Node.js 16 and older (OpenSSL 1.1.1) spelled it "self signed certificate in certificate chain". With fetch() it is the cause of "TypeError: fetch failed"; npm prints it as "npm error code SELF_SIGNED_CERT_IN_CHAIN".

Node.js tls / https / fetch — code SELF_SIGNED_CERT_IN_CHAIN (OpenSSL X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, 19)

What it means

The chain the server sent ends in a self-signed root certificate that is not among the roots Node.js trusts. On a company network this is the signature of a TLS-inspecting proxy: it re-signs every site with its own root and includes that root in the chain. Node.js uses its bundled Mozilla root list, not the operating system's store where IT installed the proxy root.

Why it happens

How to fix it

  1. 1.

    See who issued the chain

    Walk the peer certificate chain from a public site. If the top is named after your company or a security vendor, trust that root; if it is unknown, investigate before trusting anything.

    bash
    openssl s_client -connect registry.npmjs.org:443 -servername registry.npmjs.org -showcerts </dev/null 2>/dev/null \
      | grep -E '^ *[0-9]+ s:|^ *i:'
    # The last line pair shows the root the chain ends in (s: and i: identical)
  2. 2.

    Add the root with NODE_EXTRA_CA_CERTS

    The certificates in the file are added to the built-in roots for every TLS connection of the process, including npm, yarn and fetch. Set it before the process starts.

    bash
    export NODE_EXTRA_CA_CERTS=/etc/ssl/private-ca/corp-proxy-root.pem
    node app.js
  3. 3.

    Use the operating system's store

    --use-system-ca or NODE_USE_SYSTEM_CA=1 makes Node.js accept roots the OS trusts, so the proxy root deployed by IT works without copying files.

    bash
    # Managed machines already trust the proxy root in the OS store
    node --use-system-ca app.js
    NODE_USE_SYSTEM_CA=1 npm run build
  4. 4.

    Temporary diagnostic: NODE_TLS_REJECT_UNAUTHORIZED=0

    Disables certificate verification for the whole process. Only use it for one run to confirm the cause; behind an intercepting proxy it also hides any attacker that is not the proxy.

    bash
    # Temporary diagnostic only: confirms trust is the only problem, then remove it
    NODE_TLS_REJECT_UNAUTHORIZED=0 node app.js

Related errors

Browse the full signature error database