n0-computer/iroh · error · BindError

Invalid transport configuration

Error message

Invalid transport configuration

What it means

BindError::InvalidTransportConfig from iroh's socket binding code. During binding, all TransportConfig::Relay entries are collected and more than one is rejected, because the endpoint currently supports at most a single relay transport configuration.

Solutions

  1. Ensure exactly one TransportConfig::Relay in the transports list before binding.
  2. Merge multiple relay maps into the single Relay transport's relay_map instead of adding multiple relay transports.
  3. Filter out duplicate/default relay transports when constructing the endpoint config programmatically.
  4. If multiple relays are needed, run separate endpoints.

Example fix

// before
let transports = vec![
    TransportConfig::relay_map(relay_map_default),
    TransportConfig::relay_map(my_relay_map), // second relay -> error
];
// after
let transports = vec![
    TransportConfig::relay_map(my_relay_map), // single relay transport
];
Defensive patterns

Strategy: validation

Validate before calling

fn validate_relay_transports(transports: &[TransportConfig]) -> Result<(), &'static str> {
    let n = transports.iter().filter(|t| matches!(t, TransportConfig::Relay { .. })).count();
    if n > 1 { Err("at most one relay transport is supported") } else { Ok(()) }
}

Type guard

fn is_relay(t: &TransportConfig) -> bool { matches!(t, TransportConfig::Relay { .. }) }

Try / catch

match Endpoint::bind(...) {
    Err(e) if e.to_string().contains("Invalid transport configuration") => {
        // rebuild transports with a single relay entry and retry
    }
    other => other,
}

Prevention

When it happens

Trigger: Building an endpoint whose transports contain two or more TransportConfig::Relay entries, then binding. Raised in socket.rs when relay_transport_configs.len() > 1.

Common situations: Merging relay configs from multiple sources (config file + code) resulting in duplicate relay transports; appending a custom relay map while a default relay transport was already added; older code patterns that configured several relays before the single-relay restriction.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at iroh/src/socket.rs:902

            hooks,
            path_selector,
            portmapper_config,
            net_report_config,
            static_config,
            configured_addrs,
        } = opts;

        let address_lookup = address_lookup::AddressLookupServices::default();
        let port_mapper = portmapper::create_client(&portmapper_config);

        let relay_transport_configs: Vec<_> = transport_configs
            .iter()
            .filter(|t| matches!(t, TransportConfig::Relay { .. }))
            .collect();

        // Currently we only support a single relay transport
        if relay_transport_configs.len() > 1 {
            bail!(BindError::InvalidTransportConfig);
        }
        let relay_map = relay_transport_configs
            .iter()
            .filter_map(|t| {
                #[allow(irrefutable_let_patterns)]
                if let TransportConfig::Relay { relay_map, .. } = t {
                    Some(relay_map.clone())
                } else {
                    None
                }
            })
            .next()
            .unwrap_or_else(RelayMap::empty);

        let ipv6_reported = Arc::new(AtomicBool::new(false));

        let relay_actor_config = RelayActorConfig {
            my_relay: HomeRelayWatch::default(),

View on GitHub (pinned to 2b4de030ce)