fnm icon indicating copy to clipboard operation
fnm copied to clipboard

fnm fails to list remotes (error: can't get remote versions file)

Open fernan opened this issue 7 months ago • 3 comments

Hi,

not sure if this is a problem at my end. Seems like it's not (see below for full details). I'm trying to check if fnm is at the latest version, maybe update fnm or node, but I'm getting stuck at the list remotes step. Of course I can just install fresh from latest version, but I was expecting this should work:

fnm list-remote
error: can't get remote versions file: error sending request for url (https://nodejs.org/dist/index.json)

TL;DR the problem seems to be that fnm is connecting to an upstream IP address (198.41.0.4) instead of with a resolvable domain name (nodejs.org), and this fails for some reason. Or alternatively there is a badly configured upstream server at nodejs.org that does not passes the SSL handshake/connection when calling it without a domain name. Detailed debugging follows.

  1. The problem does not appear using wget, I can access this page, and the contents without issues:
wget https://nodejs.org/dist/index.json
--2025-06-02 18:14:33--  https://nodejs.org/dist/index.json
Resolving nodejs.org (nodejs.org)... 104.20.23.46, 104.20.22.46, 2606:4700:10::6814:162e, ...
Connecting to nodejs.org (nodejs.org)|104.20.23.46|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 300081 (293K) [application/json]
Saving to: ‘index.json’

index.json                                     100%[====================================================================================================>] 293.05K  --.-KB/s    in 0.1s

2025-06-02 18:14:35 (2.73 MB/s) - ‘index.json’ saved [300081/300081]
  1. If I try to investigate the issue, suspects are the addresses and ports that fnm is using to fetch the file? So a netstat gives this:
sudo watch 'netstat -np --inet | grep "fnm"'

Every 2.0s: netstat -np --inet | grep "fnm"                                                                                                              backuplex: Mon Jun  2 18:11:58 2025
tcp        0      1 172.17.9.48:47120       198.41.0.4:443          SYN_SENT    2996/fnm

This is a WSL environment, with Ubuntu 24.04 running under Windows 10. The 172.17.9.48 ip address is the one assigned by Windows to this WSL system. The connection is established to port 443 of 198.41.0.4 which maps to a.root-servers.net, and also this is one of the ip addresses that nodejs.org resolves to.

This address is OK, and I can ping without a problem

ping 198.41.0.4
PING 198.41.0.4 (198.41.0.4) 56(84) bytes of data.
64 bytes from 198.41.0.4: icmp_seq=1 ttl=54 time=134 ms
64 bytes from 198.41.0.4: icmp_seq=2 ttl=54 time=131 ms
64 bytes from 198.41.0.4: icmp_seq=3 ttl=54 time=131 ms
64 bytes from 198.41.0.4: icmp_seq=4 ttl=54 time=131 ms
^C
--- 198.41.0.4 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3173ms
rtt min/avg/max/mdev = 130.506/131.503/133.798/1.348 ms
# resolve ip address 
# 198.41.0.4 resolves to a.root-servers-net
# (online) 

# resolve domain 
dig a.root-servers.net

; <<>> DiG 9.18.30-0ubuntu0.24.04.2-Ubuntu <<>> a.root-servers.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 243
;; flags: qr rd ad; QUERY: 1, ANSWER: 10, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;a.root-servers.net.            IN      A

;; ANSWER SECTION:
a.ROOT-SERVERS.NET.     0       IN      A       198.41.0.4
a.gtld-servers.NET.     0       IN      A       192.5.6.30
a.gtld-servers.NET.     0       IN      AAAA    2001:503:a83e::2:30
b.gtld-servers.NET.     0       IN      A       192.33.14.30
b.gtld-servers.NET.     0       IN      AAAA    2001:503:231d::2:30
c.gtld-servers.NET.     0       IN      A       192.26.92.30
c.gtld-servers.NET.     0       IN      AAAA    2001:503:83eb::30
d.gtld-servers.NET.     0       IN      A       192.31.80.30
d.gtld-servers.NET.     0       IN      AAAA    2001:500:856e::30
e.gtld-servers.NET.     0       IN      A       192.12.94.30

;; Query time: 3 msec
;; SERVER: 172.17.0.1#53(172.17.0.1) (UDP)
;; WHEN: Mon Jun 02 18:21:41 UTC 2025
;; MSG SIZE  rcvd: 352

# resolve nodejs.org 
dig nodejs.org

; <<>> DiG 9.18.30-0ubuntu0.24.04.2-Ubuntu <<>> nodejs.org
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37776
;; flags: qr rd ad; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;nodejs.org.                    IN      A

;; ANSWER SECTION:
nodejs.org.             0       IN      A       104.20.22.46
nodejs.org.             0       IN      A       104.20.23.46
a.ROOT-SERVERS.NET.     0       IN      A       198.41.0.4
B.ROOT-SERVERS.NET.     0       IN      AAAA    2801:1b8:10::b
E.ROOT-SERVERS.NET.     0       IN      AAAA    2001:500:a8::e
G.ROOT-SERVERS.NET.     0       IN      AAAA    2001:500:12::d0d

;; Query time: 30 msec
;; SERVER: 172.17.0.1#53(172.17.0.1) (UDP)
;; WHEN: Mon Jun 02 18:23:19 UTC 2025
;; MSG SIZE  rcvd: 242
  1. If I now try to debug the SSL connection at port 443 I see that it fails if I use the IP address (198.41.0.4) but succeeds if I use the domain name (nodejs.org), see below. So I suspect the issue is either 1) how fnm connects upstream to list remotes (should use domain names?); or 2) how the upstream servers are configured to respond to SSL connections without a domain, e.g. it does not match a ServerName directive (apache jargon here).
# debug SSL connection at port 443 (openssl)
openssl s_client -connect 198.41.0.4:443 -prexit
40478B2EF0700000:error:8000006E:system library:BIO_connect:Connection timed out:crypto/bio/bio_sock2.c:114:calling connect()
40478B2EF0700000:error:10000067:BIO routines:BIO_connect:connect error:crypto/bio/bio_sock2.c:116:
connect:errno=110
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 0 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
# debug SSL connection at port 443 (curl, ip address )
curl -iv https://198.41.0.4
*   Trying 198.41.0.4:443...
* connect to 198.41.0.4 port 443 from 172.17.9.48 port 58914 failed: Connection timed out
* Failed to connect to 198.41.0.4 port 443 after 143944 ms: Couldn't connect to server
* Closing connection
curl: (28) Failed to connect to 198.41.0.4 port 443 after 143944 ms: Couldn't connect to server
# debug SSL connection at port 443 (curl, nodejs.org domain)
curl -iv https://nodejs.org
* Host nodejs.org:443 was resolved.
* IPv6: 2606:4700:10::6814:172e, 2606:4700:10::6814:162e
* IPv4: 104.20.22.46, 104.20.23.46
*   Trying 104.20.22.46:443...
* Connected to nodejs.org (104.20.22.46) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519 / RSASSA-PSS
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=*.nodejs.org
*  start date: Mar 12 00:00:00 2025 GMT
*  expire date: Apr 12 23:59:59 2026 GMT
*  subjectAltName: host "nodejs.org" matched cert's "nodejs.org"
*  issuer: C=GB; ST=Greater Manchester; L=Salford; O=Sectigo Limited; CN=Sectigo RSA Domain Validation Secure Server CA
*  SSL certificate verify ok.
*   Certificate level 0: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption
*   Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha384WithRSAEncryption
*   Certificate level 2: Public key type RSA (4096/152 Bits/secBits), signed using sha384WithRSAEncryption
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://nodejs.org/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: nodejs.org]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.5.0]
* [HTTP/2] [1] [accept: */*]
> GET / HTTP/2
> Host: nodejs.org
> User-Agent: curl/8.5.0
> Accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
< HTTP/2 307
HTTP/2 307
< date: Mon, 02 Jun 2025 18:30:59 GMT
date: Mon, 02 Jun 2025 18:30:59 GMT
< content-type: text/plain
content-type: text/plain
< cache-control: public, max-age=0, must-revalidate
cache-control: public, max-age=0, must-revalidate
< location: /en
location: /en
< set-cookie: NEXT_LOCALE=en; Path=/; SameSite=lax
set-cookie: NEXT_LOCALE=en; Path=/; SameSite=lax
< strict-transport-security: max-age=31536000; includeSubDomains; preload
strict-transport-security: max-age=31536000; includeSubDomains; preload
< x-vercel-id: gru1::xclgj-1748889058986-1a92e748b4ee
x-vercel-id: gru1::xclgj-1748889058986-1a92e748b4ee
< cf-cache-status: DYNAMIC
cf-cache-status: DYNAMIC
< x-content-type-options: nosniff
x-content-type-options: nosniff
< server: cloudflare
server: cloudflare
< cf-ray: 9499066a9de6f262-GRU
cf-ray: 9499066a9de6f262-GRU

<
Redirecting...
* Connection #0 to host nodejs.org left intact
  1. My setup
fnm --version
fnm 1.38.1
lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 24.04.2 LTS
Release:        24.04
Codename:       noble

fernan avatar Jun 02 '25 18:06 fernan

Same here on my macbook pro from 2017 but weirdly, it is working on my work macbook M1 from 2021. Same version 1.38.1 on both machines.

arnaud-deprez avatar Jun 30 '25 21:06 arnaud-deprez

I've done some digging on this and as far as I tell it relates the reqwest crate and in my case certs loaded via the CARGO_HTTP_CAINFO. The limitation seems to be related to https://github.com/seanmonstar/reqwest/issues/1430 and the user of default-features = false. Once removed the cargo test runs correctly locally.

Workaround is to pull the repository remove the call and build and install via cargo install --path .

dwhoban avatar Jul 14 '25 05:07 dwhoban

Self-build fixed the issue.

  • Clone this repository
  • Run cargo build --release --target x86_64-unknown-linux-gnu
  • ./target/x86_64-unknown-linux-gnu/release/fnm ls-remote # Just work

on Linux archlinux 6.15.7-arch1-1 #1 SMP PREEMPT_DYNAMIC Thu, 17 Jul 2025 21:05:29 +0000 x86_64 GNU/Linux

acro5piano avatar Jul 23 '25 01:07 acro5piano

I’m not entirely certain about this issue, but I’d like to point out that the SSL_CERT_FILE environment variable is used to specify trusted certificate authorities (CAs).

For more details on platform support, see: https://github.com/rustls/rustls-native-certs?tab=readme-ov-file#platform-support

coding-guy avatar Dec 12 '25 06:12 coding-guy