Problem description
When using TLS, ca is always required by this client: either specified via parameter or via the env var GRPC_DEFAULT_SSL_ROOTS_FILE_PATH (code).
If an application wants to rely on the system's root certificates, it must append them explicitly:
import { rootCertificates } from 'tls';
export const toGrpcRootCerts = (config: { ca?: Buffer | Buffer[] }): Buffer => {
const systemRoots = Buffer.from(rootCertificates.join('\n'));
// Use Node's built-in roots only if no custom CAs are configured
if (config.ca === undefined) {
return systemRoots;
}
const customCa = Array.isArray(config.ca) ? concatCaBuffers(config.ca) : config.ca;
// Append to Node's built-in roots so intermediate CAs can be verified
return Buffer.concat([customCa, Buffer.from('\n'), systemRoots]);
};
I wonder if the return null in the following code could be changed to return the rootCertificates:
|
export function getDefaultRootsData(): Buffer | null { |
|
if (DEFAULT_ROOTS_FILE_PATH) { |
|
if (defaultRootsData === null) { |
|
defaultRootsData = fs.readFileSync(DEFAULT_ROOTS_FILE_PATH); |
|
} |
|
return defaultRootsData; |
|
} |
|
return null; |
|
} |
Reproduction steps
- Use a TLS connection, connecting with certificates that are authorized by CAs that are verified on your machine
- Set up the client without the
ca option.
- Observe the error
Error: 14 UNAVAILABLE: No connection established. Last error: Error: unable to get issuer certificate; if the root CA is installed locally, try running Node.js with --use-system-ca.
Environment
- OS name, version and architecture: Linux Wolfi
- Node version: 24.14.1
- Node installation method: nvm
- If applicable, compiler version [e.g. clang 3.8.0-2ubuntu4]
- Package name and version
@grpc/grpc-js@1.14.3
Additional context
The only relevant log entry that I have is
{"service":{"version":"73edd814d001","type":"kibana","state":"available","node":{"roles":["background_tasks"]},"id":"U1FDpZnLRSuHt25sUlys9g"},"ecs":{"version":"9.3.0"},"@timestamp":"2026-05-27T22:10:12.903+00:00","message":"{\"stack\":\"Error: 14 UNAVAILABLE: No connection established. Last error: Error: unable to get issuer certificate; if the root CA is installed locally, try running Node.js with --use-system-ca. Resolution note: \\n at callErrorFromStatus (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/call.js:32:19)\\n at Object.onReceiveStatus (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/client.js:193:76)\\n at Object.onReceiveStatus (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:367:141)\\n at Object.onReceiveStatus (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:327:181)\\n at /usr/share/kibana/node_modules/@grpc/grpc-js/build/src/resolving-call.js:135:78\\n at processTicksAndRejections (node:internal/process/task_queues:85:11)\\nfor call at\\n at ServiceClientImpl.makeUnaryRequest (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/client.js:161:32)\\n at ServiceClientImpl.export (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/make-client.js:105:19)\\n at /usr/share/kibana/node_modules/@opentelemetry/otlp-grpc-exporter-base/build/src/grpc-exporter-transport.js:98:32\\n at new Promise (<anonymous>)\\n at GrpcExporterTransport.send (/usr/share/kibana/node_modules/@opentelemetry/otlp-grpc-exporter-base/build/src/grpc-exporter-transport.js:87:16)\\n at OTLPExportDelegate.export (/usr/share/kibana/node_modules/@opentelemetry/otlp-exporter-base/build/src/otlp-export-delegate.js:47:56)\\n at OTLPLogExporter.export (/usr/share/kibana/node_modules/@opentelemetry/otlp-exporter-base/build/src/OTLPExporterBase.js:19:30)\\n at /usr/share/kibana/node_modules/@opentelemetry/sdk-logs/build/src/export/BatchLogRecordProcessorBase.js:69:28\\n at new Promise (<anonymous>)\\n at ExportOperation._exportWithTimeout (/usr/share/kibana/node_modules/@opentelemetry/sdk-logs/build/src/export/BatchLogRecordProcessorBase.js:64:16)\",\"message\":\"14 UNAVAILABLE: No connection established. Last error: Error: unable to get issuer certificate; if the root CA is installed locally, try running Node.js with --use-system-ca. Resolution note: \",\"code\":\"14\",\"details\":\"No connection established. Last error: Error: unable to get issuer certificate; if the root CA is installed locally, try running Node.js with --use-system-ca. Resolution note: \",\"metadata\":\"[object Object]\",\"name\":\"Error\"}","log":{"level":"ERROR","logger":"telemetry"},"process":{"pid":7,"uptime":27187.550138107},"span":{"id":"c260aa5603661248"},"trace":{"id":"32b429e7a682b92e957ed8026ca706be"}}
Problem description
When using TLS,
cais always required by this client: either specified via parameter or via the env varGRPC_DEFAULT_SSL_ROOTS_FILE_PATH(code).If an application wants to rely on the system's root certificates, it must append them explicitly:
I wonder if the
return nullin the following code could be changed to return the rootCertificates:grpc-node/packages/grpc-js/src/tls-helpers.ts
Lines 27 to 35 in a558430
Reproduction steps
caoption.Error: 14 UNAVAILABLE: No connection established. Last error: Error: unable to get issuer certificate; if the root CA is installed locally, try running Node.js with --use-system-ca.Environment
- If applicable, compiler version [e.g. clang 3.8.0-2ubuntu4]@grpc/grpc-js@1.14.3Additional context
The only relevant log entry that I have is
{"service":{"version":"73edd814d001","type":"kibana","state":"available","node":{"roles":["background_tasks"]},"id":"U1FDpZnLRSuHt25sUlys9g"},"ecs":{"version":"9.3.0"},"@timestamp":"2026-05-27T22:10:12.903+00:00","message":"{\"stack\":\"Error: 14 UNAVAILABLE: No connection established. Last error: Error: unable to get issuer certificate; if the root CA is installed locally, try running Node.js with --use-system-ca. Resolution note: \\n at callErrorFromStatus (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/call.js:32:19)\\n at Object.onReceiveStatus (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/client.js:193:76)\\n at Object.onReceiveStatus (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:367:141)\\n at Object.onReceiveStatus (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:327:181)\\n at /usr/share/kibana/node_modules/@grpc/grpc-js/build/src/resolving-call.js:135:78\\n at processTicksAndRejections (node:internal/process/task_queues:85:11)\\nfor call at\\n at ServiceClientImpl.makeUnaryRequest (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/client.js:161:32)\\n at ServiceClientImpl.export (/usr/share/kibana/node_modules/@grpc/grpc-js/build/src/make-client.js:105:19)\\n at /usr/share/kibana/node_modules/@opentelemetry/otlp-grpc-exporter-base/build/src/grpc-exporter-transport.js:98:32\\n at new Promise (<anonymous>)\\n at GrpcExporterTransport.send (/usr/share/kibana/node_modules/@opentelemetry/otlp-grpc-exporter-base/build/src/grpc-exporter-transport.js:87:16)\\n at OTLPExportDelegate.export (/usr/share/kibana/node_modules/@opentelemetry/otlp-exporter-base/build/src/otlp-export-delegate.js:47:56)\\n at OTLPLogExporter.export (/usr/share/kibana/node_modules/@opentelemetry/otlp-exporter-base/build/src/OTLPExporterBase.js:19:30)\\n at /usr/share/kibana/node_modules/@opentelemetry/sdk-logs/build/src/export/BatchLogRecordProcessorBase.js:69:28\\n at new Promise (<anonymous>)\\n at ExportOperation._exportWithTimeout (/usr/share/kibana/node_modules/@opentelemetry/sdk-logs/build/src/export/BatchLogRecordProcessorBase.js:64:16)\",\"message\":\"14 UNAVAILABLE: No connection established. Last error: Error: unable to get issuer certificate; if the root CA is installed locally, try running Node.js with --use-system-ca. Resolution note: \",\"code\":\"14\",\"details\":\"No connection established. Last error: Error: unable to get issuer certificate; if the root CA is installed locally, try running Node.js with --use-system-ca. Resolution note: \",\"metadata\":\"[object Object]\",\"name\":\"Error\"}","log":{"level":"ERROR","logger":"telemetry"},"process":{"pid":7,"uptime":27187.550138107},"span":{"id":"c260aa5603661248"},"trace":{"id":"32b429e7a682b92e957ed8026ca706be"}}