Skip to content

Node 26: secure channels to an IP address fail with ERR_INVALID_ARG_VALUE because channel-credentials sets servername to the IP #3131

Closed as duplicate

Description

@listenrightmeow

Problem description

On Node.js 26, tls.connect throws when servername is an IP address:

TypeError [ERR_INVALID_ARG_VALUE]: The property 'options.servername' Setting the TLS ServerName to an IP address is not permitted.. Received '127.0.0.1'

@grpc/grpc-js sets connectionOptions.servername = remoteHost unconditionally when grpc.ssl_target_name_override is not given (build/src/channel-credentials.js, around lines 153-163 in 1.14.7). So every secure channel to an IP-address target fails to connect on Node 26, including 127.0.0.1 and [::1]. RFC 6066 section 3 says SNI must not carry a literal IP address, so the name should not be sent in that case. Verifying the certificate's IP SAN is separate and stays with checkServerIdentity.

Reproduction

The Node-level behaviour (Node 26.11.1):

const tls = require('tls');
tls.connect({ host: '127.0.0.1', port: 9, servername: '127.0.0.1' }); // throws ERR_INVALID_ARG_VALUE
tls.connect({ host: '127.0.0.1', port: 9, servername: 'localhost' }); // connects normally (ECONNREFUSED here, nothing listening)

Through grpc-js: @kurrent/kurrentdb-client 1.3.2 with kurrentdb://user:pass@127.0.0.1:2113?tls=true&tlsVerifyCert=false fails every call on Node 26.11.1 with 14 UNAVAILABLE: No connection established. Last error: TypeError [ERR_INVALID_ARG_VALUE]: ... Setting the TLS ServerName to an IP address is not permitted.. Received '127.0.0.1'. The same code passes on Node 24, and it passes on Node 26 with the host localhost.

Environment

  • Node.js 26.11.1 (macOS, x86_64)
  • @grpc/grpc-js 1.14.7, the latest at the time of writing

Expected behaviour

servername is set only when the remote host is not an IP address (net.isIP(host) === 0), or when grpc.ssl_target_name_override is given. An IP target connects, and the certificate's IP SAN is still verified when rejectUnauthorized is true.

Additional context

Downstream clients such as kurrentdb-client expose no channel option for this, so the only workaround they have is to rewrite the target host.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions