n0-computer/iroh · error · ConnectWithOptsError

SelfConnect

SelfConnect

Error message

Connecting to ourself is not supported

What it means

An endpoint connection attempt targeted the endpoint's own EndpointId. A node cannot open a QUIC connection to itself through the same endpoint, so connect_with_opts rejects this immediately with ConnectWithOptsError::SelfConnect before any networking happens.

Solutions

  1. Filter out the local endpoint's own EndpointId before calling connect.
  2. Compare the target against endpoint.id() and skip/self-handle those entries.
  3. For loopback communication use an in-process channel instead of a QUIC connection.
  4. In peer-discovery code, exclude the node's own advertised addresses from the dial list.

Example fix

// before
endpoint.connect(peer.endpoint_id, alpn).await?;
// after
if peer.endpoint_id != endpoint.id() {
    endpoint.connect(peer.endpoint_id, alpn).await?;
}
Defensive patterns

Strategy: validation

Validate before calling

fn can_connect(ep: &Endpoint, target: EndpointId) -> bool { target != ep.id() }

Type guard

fn remote_id(ep: &Endpoint, id: EndpointId) -> Option<EndpointId> { (id != ep.id()).then_some(id) }

Try / catch

match endpoint.connect(id, alpn).await {
    Err(e) if matches!(&e, ConnectWithOptsError::SelfConnect) => { /* skip self, not fatal */ }
    other => other?,
}

Prevention

When it happens

Trigger: Calling endpoint.connect(own_endpoint_id, alpn) (or passing an endpoint_addr whose endpoint_id equals self.id()) — e.g. dialing an address the node itself advertised, or a peer registry that returned this node's own entry.

Common situations: Bootstrapping nodes that add themselves to their peer list, tests reusing one endpoint for both sides, config files with a self-referencing relay/home address, discovering your own addresses via a discovery service and then dialing them.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of n0-computer/iroh@2b4de030ce (2026-09-08). Data as JSON: /api/errors/ffd7c0c45d7f5367. Report an issue: GitHub.

Appendix: source

Thrown at iroh/src/endpoint.rs:1122

        options: ConnectOptions,
    ) -> Result<Connecting, ConnectWithOptsError> {
        if self.is_closed() {
            return Err(e!(ConnectWithOptsError::EndpointClosed));
        }

        let endpoint_addr: EndpointAddr = endpoint_addr.into();
        let endpoint_id = endpoint_addr.id;

        Span::current().record("remote", tracing::field::display(endpoint_id.fmt_short()));

        if let BeforeConnectOutcome::Reject =
            self.inner.hooks.before_connect(&endpoint_addr, alpn).await
        {
            return Err(e!(ConnectWithOptsError::LocallyRejected));
        }

        // Connecting to ourselves is not supported.
        ensure!(endpoint_id != self.id(), ConnectWithOptsError::SelfConnect);
        ensure!(!alpn.is_empty(), ConnectWithOptsError::InvalidAlpn);

        event!(
            target: "iroh::_events::conn::connecting",
            tracing::Level::DEBUG,
            remote_id = %endpoint_id.fmt_short(),
            alpn = %String::from_utf8_lossy(alpn),
        );

        debug!(
            relay_url = ?endpoint_addr.relay_urls().next().cloned(),
            ip_addresses = ?endpoint_addr.ip_addrs().cloned().collect::<Vec<_>>(),
            "connecting",
        );

        let mapped_addr = self.inner.resolve_remote(endpoint_addr).await??;

        let transport_config = options

View on GitHub (pinned to 2b4de030ce)