ipfs/kubo · warning · ErrConnNotFound

conn not found

Error message

conn not found

What it means

ErrConnNotFound is a sentinel error of the CoreAPI swarm interface, defined in core/coreiface/swarm.go. Disconnect returns it when the multiaddr form is used (core/coreapi/swarm.go:89): the node enumerated its live connections and none of them is over the given address, so there is nothing to close.

Source

Thrown at core/coreiface/swarm.go:17

package iface

import (
	"context"
	"errors"
	"time"

	"github.com/libp2p/go-libp2p/core/network"
	"github.com/libp2p/go-libp2p/core/peer"
	"github.com/libp2p/go-libp2p/core/protocol"

	ma "github.com/multiformats/go-multiaddr"
)

var (
	ErrNotConnected = errors.New("not connected")
	ErrConnNotFound = errors.New("conn not found")
)

// ConnectionInfo contains information about a peer
type ConnectionInfo interface {
	// ID returns PeerID
	ID() peer.ID

	// Address returns the multiaddress via which we are connected with the peer
	Address() ma.Multiaddr

	// Direction returns which way the connection was established
	Direction() network.Direction

	// Latency returns last known round trip time to the peer
	Latency() (time.Duration, error)

	// Streams returns list of streams established with the peer
	Streams() ([]protocol.ID, error)

View on GitHub (pinned to 329838acdf)

Solutions

  1. Check api.Swarm().Peers(ctx) and disconnect using the exact Address() strings from its output, refreshed at call time
  2. Prefer the peer-ID form: Disconnect(ctx, peer.ID) — it closes the connection regardless of which address it uses (returning ErrNotConnected instead if already gone)
  3. Accept errors.Is(err, coreiface.ErrConnNotFound) as a no-op success in cleanup paths

Example fix

// before
addrs, _ := api.Swarm().Peers(ctx) // stale snapshot
_ = addrs[0].Address().String()     // connection since dropped
err := api.Swarm().Disconnect(ctx, staleAddr) // ErrConnNotFound

// after
peers, _ := api.Swarm().Peers(ctx)
for _, p := range peers {
    if p.ID() == targetID {
        err := api.Swarm().Disconnect(ctx, p.ID())
        if err != nil && !errors.Is(err, coreiface.ErrConnNotFound) {
            return err
        }
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

peers, err := api.Swarm().Peers(ctx)
if err != nil {
    return err
}
found := false
for _, p := range peers {
    if p.Address().Equal(targetAddr) {
        found = true
        break
    }
}
if !found {
    return nil // nothing to disconnect
}
err = api.Swarm().Disconnect(ctx, targetAddr)

Type guard

func isConnNotFoundErr(err error) bool {
    return errors.Is(err, coreiface.ErrConnNotFound)
}

Try / catch

err := api.Swarm().Disconnect(ctx, addr)
switch {
case err == nil:
    // connection closed
case errors.Is(err, coreiface.ErrConnNotFound):
    // no live connection on that address: treat as no-op
default:
    return fmt.Errorf("disconnect %s: %w", addr, err)
}

Prevention

When it happens

Trigger: Calling api.Swarm().Disconnect(ctx, addr) with a multiaddr that does not match any active connection: the connection dropped already (so Peerstore keeps the addr but no conn exists), a stale relay/circuit address, a DNS address that resolved differently from the dialed form, or a wrong port/scheme typo.

Common situations: Disconnecting a specific connection after a relay circuit was recycled; peers that connected via a different address than advertised (e.g. AutoTLS *.libp2p.direct vs raw TCP); reconnect-and-disconnect races in tests; hardcoding addresses from an earlier Peers() snapshot.

Related errors


AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03). Data as JSON: /api/errors/4148920689480ae7. Report an issue: GitHub.