denoland/deno · error
invalid IPv4 address
Error message
invalid IPv4 address
What it means
Thrown by Deno's node:dgram implementation of socket.setMulticastInterface (op_node_udp_set_multicast_interface, ext/node/ops/udp.rs). When the socket is IPv4 (is_ipv6=false), the interface argument is parsed with Rust's Ipv4Addr::parse; any value that is not a literal dotted-quad IPv4 address fails with ErrorKind::InvalidInput and this message. This mirrors libuv, which returns EINVAL for an unparseable multicast interface address.
Source
Thrown at ext/node/ops/udp.rs:375
sock_ref.set_ttl(ttl)?;
Ok(())
}
#[op2(fast)]
pub fn op_node_udp_set_multicast_interface(
state: &mut OpState,
#[smi] rid: ResourceId,
is_ipv6: bool,
#[string] interface_address: &str,
) -> Result<(), NodeUdpError> {
let resource = state.resource_table.get::<NodeUdpSocketResource>(rid)?;
let sock_ref = socket2::SockRef::from(&resource.socket);
if is_ipv6 {
let index = ipv6_interface_index(interface_address)?;
sock_ref.set_multicast_if_v6(index)?;
} else {
let addr: Ipv4Addr = interface_address.parse().map_err(|_| {
NodeUdpError::Io(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"invalid IPv4 address",
))
})?;
sock_ref.set_multicast_if_v4(&addr)?;
}
Ok(())
}
/// Parse an IPv6 interface address string to a network interface index.
/// Matches libuv's `uv__udp_set_multicast_interface6` behavior:
/// - Parses IPv6 address strings like `::%lo0`, `::%1`, `::`
/// - Extracts scope_id and resolves interface names via if_nametoindex
/// - Returns EINVAL for empty or unparseable addresses
fn ipv6_interface_index(interface_address: &str) -> Result<u32, NodeUdpError> {
let einval =
|| NodeUdpError::Io(std::io::Error::from_raw_os_error(libc::EINVAL));
View on GitHub (pinned to a961cdec3b)
Solutions
- Pass a valid IPv4 literal matching the socket family: '0.0.0.0' for the default interface, or the address of a NIC from os.networkInterfaces() where family === 'IPv4'.
- If the socket is IPv6, pass an IPv6 literal with optional zone ('::' or 'fe80::1%eth0'); do not mix families between bind() and setMulticastInterface().
- Validate the value with node:net isIPv4()/isIPv6() before calling the API and fail fast with the offending value in the message.
- If the value comes from config, log it when EINVAL is caught so the bad input is visible.
Example fix
// before
sock.setMulticastInterface(process.env.MULTICAST_IFACE ?? "eth0"); // EINVAL: invalid IPv4 address
// after
import { isIPv4, isIPv6 } from "node:net";
import { networkInterfaces } from "node:os";
const anyV4 = Object.values(networkInterfaces()).flat().find(a => a?.family === "IPv4")?.address ?? "0.0.0.0";
const iface = process.env.MULTICAST_IFACE ?? anyV4;
if (sock.address().family === "IPv4" && !isIPv4(iface)) throw new Error(`MULTICAST_IFACE must be IPv4, got ${iface}`);
if (sock.address().family === "IPv6" && !isIPv6(iface)) throw new Error(`MULTICAST_IFACE must be IPv6, got ${iface}`);
sock.setMulticastInterface(iface); Defensive patterns
Strategy: validation
Validate before calling
import { isIPv4 } from "node:net";
const iface = process.env.MULTICAST_IFACE ?? "0.0.0.0";
if (!isIPv4(iface)) throw new Error(`MULTICAST_IFACE must be an IPv4 literal, got: ${iface}`);
sock.setMulticastInterface(iface); Type guard
import { isIPv4 } from "node:net";
const isIPv4Literal = (v: string): v is `${number}.${number}.${number}.${number}` => isIPv4(v); Try / catch
try { sock.setMulticastInterface(iface); } catch (e) { if (e instanceof Error && /invalid IPv4 address/.test(e.message)) throw new Error(`bad MULTICAST_IFACE: ${JSON.stringify(iface)}`); throw e; } Prevention
- Never pass interface names or hostnames to setMulticastInterface; only IP literals.
- Pick the interface from os.networkInterfaces() filtered by the socket's family so families can never mismatch.
- Validate config-supplied addresses at startup with node:net isIPv4/isIPv6 and fail fast.
When it happens
Trigger: Calling dgram socket.setMulticastInterface(x) on a socket bound to IPv4 where x is not an IPv4 literal: an IPv6 address ('::1'), an interface name ('eth0'), a hostname ('localhost'), an empty string, or a scoped address ('fe80::1%eth0'). Only dotted-quad literals like '0.0.0.0', '127.0.0.1', or a local NIC address such as '192.168.1.5' are accepted.
Common situations: Config values copied from C examples that use interface names; code ported between IPv4 and IPv6 sockets without changing the interface argument; env-provided MULTICAST_IFACE misconfigured; confusion between 'any' (0.0.0.0) and loopback; passing the result of os.networkInterfaces() fields of the wrong family.
Related errors
- ERR_MISSING_ARGS
- ERR_SOCKET_BAD_TYPE
- ERR_SOCKET_ALREADY_BOUND
- ERR_INVALID_FD_TYPE
- ERR_SOCKET_DGRAM_IS_CONNECTED
AI-assisted analysis of denoland/deno@a961cdec3b (2026-08-20).
Data as JSON: /api/errors/04ce1d4f49342956.
Report an issue: GitHub.