This error occurs when Node.js attempts to read a certificate or private key file that is not properly formatted in PEM format. The OpenSSL library cannot find the required PEM header markers or the file structure is malformed.
This error originates from OpenSSL's PEM parsing routines when Node.js tries to load TLS/SSL certificates or private keys. PEM (Privacy Enhanced Mail) is a base64-encoded format that requires specific header and footer markers. The "no start line" message means the OpenSSL library could not find a valid PEM header like `-----BEGIN CERTIFICATE-----` or `-----BEGIN PRIVATE KEY-----`, or the file structure doesn't match the expected PEM format. This commonly happens when setting up HTTPS servers, configuring TLS clients, or working with JWT signing keys. The Node.js `https`, `tls`, and `crypto` modules all rely on OpenSSL to parse these files, so any formatting issue will trigger this error.
Open your certificate or key file and confirm it has the required markers:
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKJ... (base64 content)
... (more lines)
-----END CERTIFICATE-----For private keys:
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhki... (base64 content)
-----END PRIVATE KEY-----Or for RSA keys:
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA... (base64 content)
-----END RSA PRIVATE KEY-----If these markers are missing, your file is not in PEM format.
PEM files must have actual newline characters. If your certificate looks like this:
-----BEGIN CERTIFICATE-----MIIDXTCCAkWgAwIBA...-----END CERTIFICATE-----It needs newlines added:
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBA...
(64-character lines)
-----END CERTIFICATE-----If loading from environment variables or databases, ensure newlines are preserved:
const privateKey = process.env.PRIVATE_KEY.replace(/\\n/g, '\n');Verify your HTTPS/TLS configuration uses the right files:
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('path/to/private-key.pem'), // Private key here
cert: fs.readFileSync('path/to/certificate.pem') // Certificate here
};
const server = https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('Hello secure world!');
});Common mistakes:
- Swapping the key and cert files
- Using a certificate when a CA bundle is expected
- Missing intermediate certificates in chain
Use OpenSSL command-line tools to verify the file format:
For certificates:
openssl x509 -in certificate.pem -text -nooutFor private keys:
openssl rsa -in private-key.pem -checkIf these commands fail with similar errors, the file is definitely malformed. If they succeed but Node.js still fails, check for file encoding issues:
file certificate.pem
# Should show: ASCII text or UTF-8 Unicode textWhen loading certificates from environment variables (common in Docker/cloud deployments):
// Wrong - treats \n as literal characters
const cert = process.env.SSL_CERT;
// Correct - converts escaped newlines to actual newlines
const cert = process.env.SSL_CERT.replace(/\\n/g, '\n');
// Alternative: use Buffer
const cert = Buffer.from(process.env.SSL_CERT, 'base64').toString('utf8');In your .env file or environment configuration:
# Multi-line format (preferred)
SSL_CERT="-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKJ...
-----END CERTIFICATE-----"
# Or single-line with \n (must be unescaped in code)
SSL_CERT="-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWg...\n-----END CERTIFICATE-----"Ensure the file is saved as UTF-8 without BOM:
# Check encoding
file -i certificate.pem
# Convert if necessary
iconv -f UTF-16 -t UTF-8 certificate.pem > certificate-utf8.pemRemove any BOM markers or trailing whitespace:
# Remove BOM
sed -i '1s/^\xEF\xBB\xBF//' certificate.pem
# Remove trailing whitespace
sed -i 's/[[:space:]]*$//' certificate.pemYou can also regenerate a clean PEM file from the certificate:
openssl x509 -in certificate.crt -out certificate.pem -outform PEMCertificate Chain Ordering: When providing a certificate chain, the order matters. Your server certificate should come first, followed by intermediate certificates, then the root CA. Each certificate needs its own PEM headers/footers:
-----BEGIN CERTIFICATE-----
(your server cert)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(intermediate cert)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(root CA cert)
-----END CERTIFICATE-----Alternative PEM Headers: Different key types use different headers. Modern keys use -----BEGIN PRIVATE KEY----- (PKCS#8), while older RSA keys use -----BEGIN RSA PRIVATE KEY-----. Node.js supports both formats.
Docker and CI/CD Considerations: When mounting secrets in containers, ensure volume mounts preserve newlines. Some orchestration platforms base64-encode secrets by default, requiring decoding before use.
passphrase-protected Keys: If your private key requires a passphrase, provide it in the options:
const options = {
key: fs.readFileSync('encrypted-key.pem'),
passphrase: 'your-passphrase'
};Debugging Production Issues: In production environments where you cannot easily inspect files, log the first and last 50 characters of the loaded certificate (excluding sensitive content) to verify headers are preserved:
const cert = fs.readFileSync('cert.pem', 'utf8');
console.log('First 50:', cert.substring(0, 50));
console.log('Last 50:', cert.substring(cert.length - 50));Error: EMFILE: too many open files, watch
EMFILE: fs.watch() limit exceeded
Error: Middleware next() called multiple times (next() invoked twice)
Express middleware next() called multiple times
Error: Worker failed to initialize (worker startup error)
Worker failed to initialize in Node.js
Error: EMFILE: too many open files, open 'file.txt'
EMFILE: too many open files
Error: cluster.fork() failed (cannot create child process)
cluster.fork() failed - Cannot create child process