Skip to content

kad-dht: getClosestPeers consistently times out #3419

@tabcat

Description

@tabcat
  • Version: @libp2p/kad-dht@16.1.5, libp2p@3.1.5

  • Platform: Linux x86_64, Node.js v24.12.0

  • Subsystem: KadDHT

Severity:

High - The main functionality of the application does not work.

Description:

getClosestPeers consistently times out when searching for a random key on the Amino DHT, even with many connected peers and a generous timeout.

  • What I did: Created a libp2p node with the Amino DHT (/ipfs/kad/1.0.0), TCP transport, noise/TLS encrypters, yamux/mplex muxers, and bootstrap peer discovery. After waiting for bootstrap connections, called getClosestPeers with a random CID key (sha256-hashed random bytes).
  • What happened: The call times out without returning any FINAL_PEER events. This happens consistently — 0/10 runs succeeded with a 10s timeout even when 85 connected peers were present. With a 30s timeout and 10s bootstrap wait, still 0/2.
  • What I expected: getClosestPeers should complete and return the closest peers to the given key within a reasonable time, especially when the node has dozens of active connections.

Note: searching for the node's own peer ID (node.peerId.toMultihash().bytes) works reliably because the initial self-query populates the routing table for that region of the keyspace. Random keys do not benefit from this and expose the underlying issue.

Steps to reproduce the error:

import { randomBytes } from "node:crypto"
import { noise } from "@chainsafe/libp2p-noise"
import { yamux } from "@chainsafe/libp2p-yamux"
import { bootstrap } from "@libp2p/bootstrap"
import { identify } from "@libp2p/identify"
import { kadDHT, removePrivateAddressesMapper, EventTypes } from "@libp2p/kad-dht"
import { mplex } from "@libp2p/mplex"
import { ping } from "@libp2p/ping"
import { tcp } from "@libp2p/tcp"
import { tls } from "@libp2p/tls"
import { createLibp2p } from "libp2p"
import { CID } from "multiformats/cid"
import { sha256 } from "multiformats/hashes/sha2"

const node = await createLibp2p({
  addresses: { listen: ["/ip4/0.0.0.0/tcp/0"] },
  transports: [tcp()],
  connectionEncrypters: [noise(), tls()],
  streamMuxers: [yamux(), mplex()],
  peerDiscovery: [
    bootstrap({
      list: [
        "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
        "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
        "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
        "/dnsaddr/va1.bootstrap.libp2p.io/p2p/12D3KooWKnDdG3iXw9eTFijk3EWSunZcFi54Zka4wmtqtt6rPxc8",
        "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
      ],
    }),
  ],
  services: {
    dht: kadDHT({
      protocol: "/ipfs/kad/1.0.0",
      peerInfoMapper: removePrivateAddressesMapper,
    }),
    identify: identify(),
    ping: ping(),
  },
})

// wait for bootstrap connections
await new Promise((resolve) => setTimeout(resolve, 10_000))
console.log("connected peers:", node.getPeers().length)

// generate a random CID to search for
const hash = await sha256.digest(randomBytes(32))
const cid = CID.createV1(0x55, hash)

console.log("calling getClosestPeers...")
try {
  for await (const event of node.services.dht.getClosestPeers(cid.multihash.bytes, {
    signal: AbortSignal.timeout(30_000),
  })) {
    if (event.type === EventTypes.FINAL_PEER) {
      console.log("found peer:", event.peer.id.toString())
    }
  }
  console.log("completed")
} catch (e) {
  console.error("failed:", e) // consistently hits TimeoutError
}

await node.stop()

Typical output:

connected peers: 54
calling getClosestPeers...
failed: DOMException [TimeoutError]: The operation was aborted due to timeout

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High: Likely tackled by core team if no one steps upkind/bugA bug in existing code (including security flaws)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions