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
- Ensure exactly one TransportConfig::Relay in the transports list before binding.
- Merge multiple relay maps into the single Relay transport's relay_map instead of adding multiple relay transports.
- Filter out duplicate/default relay transports when constructing the endpoint config programmatically.
- 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
- Keep exactly one TransportConfig::Relay entry in endpoint config
- Merge multiple relay maps into one relay_map instead of multiple relay transports
- Sanitize merged configs (file + code) for duplicate relay entries
- Validate transports programmatically before binding
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
- The relay is rate-limiting this endpoint; outbound relay…
- Only a single default address can be set per IP family
- UnexpectedUpgradeStatus
- ExceedsMaxPacketSize
- EmptyPacket
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)