"self signed certificate in certificate chain" is TLS's trust verification working exactly as intended — a certificate that isn't signed by a certificate authority your system trusts is, by design, rejected, since accepting arbitrary self-signed certificates would defeat the entire point of TLS's identity verification.
This error means the TLS certificate presented by the server you're connecting to (or one in its certificate chain) is self-signed rather than signed by a certificate authority (CA) your system's trust store recognizes — this is common and expected for internal development servers, corporate proxies, and certain internal infrastructure, but represents a genuine security concern if it's unexpectedly happening against a service that should have a properly CA-signed certificate.
Why This Error Happens
TLS establishes trust through a chain of signatures ultimately rooted in a small set of certificate authorities that operating systems and browsers ship with as trusted by default. A self-signed certificate breaks this chain — it's signed by itself rather than by a recognized authority — so any client performing proper certificate validation will reject it unless that specific certificate (or its issuing CA, for internal/private CAs) has been explicitly added to the trust store being used.
Reproducing and Diagnosing the Error
Connecting to a local development server or internal service using a self-signed certificate:
const response = await fetch("https://localhost:8443/api/data");
// Error: self signed certificate
// (Node.js's default TLS verification correctly rejects it)
Diagnosing whether this is expected (internal/dev service) or concerning (should be a public, CA-signed service):
openssl s_client -connect localhost:8443 -showcerts
# Inspect the certificate chain to confirm it's self-signed and understand
# what it's actually presenting
Core Concepts Behind This Error
Disabling certificate verification entirely is almost never the correct fix, even though it's the fastest way to make the error disappear — doing so removes TLS's protection against man-in-the-middle attacks for that connection entirely, which is a meaningful security regression, not just a suppressed warning.
The correct fix depends heavily on context: local development against your own self-signed certificate has different appropriate solutions than connecting to a third-party service that unexpectedly presents a self-signed certificate (which may indicate a misconfiguration on their end, or in rarer cases, an actual security concern worth investigating).
Adding a specific self-signed certificate (or internal CA) to your trust store explicitly is the correct approach for legitimate internal infrastructure — corporate environments, internal microservices, and local development setups commonly use internally-issued certificates that should be explicitly trusted, rather than having verification disabled globally.
NODE_TLS_REJECT_UNAUTHORIZED=0 disables certificate verification for the entire Node.js process, which is a broad, dangerous setting if used carelessly — it's sometimes seen in tutorials or quick fixes for local development, but should never be used in any environment handling real user data or production traffic, and even for development, a more targeted fix is preferable.
Fixing "Self Signed Certificate in Certificate Chain"
Fix 1: For local development, explicitly trust your specific self-signed certificate rather than disabling verification process-wide:
import https from "node:https";
import fs from "node:fs";
const agent = new https.Agent({
ca: fs.readFileSync("./certs/dev-cert.pem"), // explicitly trust this specific cert
});
const response = await fetch("https://localhost:8443/api/data", { agent } as any);
Fix 2: For internal infrastructure using a private/internal CA, add that CA to your system or process trust store, rather than trusting individual leaf certificates one at a time:
# Node.js: point at an internal CA bundle explicitly
NODE_EXTRA_CA_CERTS=/path/to/internal-ca.pem node server.js
Fix 3: If encountering this unexpectedly against a service that should have a properly CA-signed certificate, treat it as a configuration issue on that service to fix, not something to work around on your end — a public-facing production service presenting a self-signed certificate is a misconfiguration (or worth investigating further) rather than something your client should simply accept.
Is It Ever Acceptable to Disable Certificate Verification Entirely?
Only in tightly-scoped, temporary local development scenarios where you fully understand and accept the tradeoff, and even then, a more targeted fix (trusting the specific certificate or internal CA) is preferable. Never in any environment handling real traffic, real user data, or anything resembling production — disabling verification removes TLS's core security guarantee, and the more scoped fixes above address the underlying trust problem correctly without that tradeoff.
Preventing This Error From Becoming a Security Shortcut
Set up explicit, scoped certificate trust (a specific dev certificate or an internal CA bundle) as the standard pattern for any internal or development infrastructure using self-signed certificates, documented clearly enough that engineers don't reach for disabling verification entirely as a faster-seeming shortcut. Audit any existing use of NODE_TLS_REJECT_UNAUTHORIZED=0 or equivalent verification-disabling settings in your codebase and CI configuration, replacing them with scoped trust configuration wherever found.
If you hit this error, resist the fastest-looking fix (disabling verification) and instead identify whether you're dealing with legitimate internal infrastructure (fix: trust the specific cert/CA) or an unexpected misconfiguration on a service that should be properly CA-signed (fix: raise it with whoever owns that service).