denoland/deno · error · TypeError
ERR_INVALID_FD_TYPE
ERR_INVALID_FD_TYPE
Error message
Unsupported fd type: ${type} What it means
When bind() receives options with an integer fd > 0, dgram opens that existing descriptor instead of creating a socket. It inspects the descriptor with guessHandleType(fd) and requires 'UDP'; any other kind — TCP, pipe, TTY, file — throws ERR_INVALID_FD_TYPE with the detected type embedded in the message.
Source
Thrown at ext/node/polyfills/dgram.ts:460
}
// Open an existing fd instead of creating a new one.
if (isBindOptions(port) && isInt32(port.fd!) && port.fd! > 0) {
const fd = port.fd!;
const state = this[kStateSymbol];
// TODO(cmorten): here we deviate somewhat from the Node implementation which
// makes use of the https://nodejs.org/api/cluster.html module to run servers
// across a "cluster" of Node processes to take advantage of multi-core
// systems.
//
// Though Deno has has a Worker capability from which we could simulate this,
// for now we assert that we are _always_ on the primary process.
const type = guessHandleType(fd);
if (type !== "UDP") {
throw new ERR_INVALID_FD_TYPE(type);
}
const err = state.handle!.open(fd);
if (err) {
throw errnoException(err, "open");
}
startListening(this);
return this;
}
let address: string;
if (isBindOptions(port)) {
address = port.address || "";
port = port.port;View on GitHub (pinned to 89f33cbef2)
Solutions
- Only pass fds that came from a real UDP socket
- For systemd socket activation, declare ListenDatagram= (not ListenStream=) so the inherited fd is UDP
- Drop the fd entirely and let dgram create its own socket: createSocket('udp4').bind(port)
Example fix
// before
const sock = dgram.createSocket("udp4");
sock.bind({ fd: inheritedTcpFd });
// after
const sock = dgram.createSocket("udp4");
sock.bind(port); Defensive patterns
Strategy: try-catch
Validate before calling
function isUdpFdCandidate(fd) {
// fd 0/1/2 are std streams (TTY/PIPE) and can never be UDP
return typeof fd === "number" && Number.isInteger(fd) && fd > 2 && fdKnownToBeDatagram;
}
sock.bind(isUdpFdCandidate(fd) ? { fd } : { port }); Try / catch
try {
sock.bind({ fd });
} catch (e) {
if (e.code === "ERR_INVALID_FD_TYPE") {
sock = dgram.createSocket("udp4"); // fall back: let dgram create its own socket
sock.bind(port);
} else throw e;
} Prevention
- Only inherit fds you opened as UDP sockets
- Match systemd units: ListenDatagram= with dgram, ListenStream= with net
- Log fd-type mismatches loudly — they indicate wiring bugs, not runtime flakiness
When it happens
Trigger: sock.bind({ fd: 1 }) or fd: 0 (stdin/stdout are TTY/PIPE, never UDP); passing a TCP listener's fd from a net.Server; passing a file fd from fs.open; fd-passing setups where the wrong descriptor index is used.
Common situations: systemd socket activation declaring ListenStream= (TCP) while the app uses dgram; SO_REUSEPORT fd sharing across processes that mixes net and dgram; test harnesses wiring arbitrary fds into the socket.
Related errors
- ERR_MISSING_ARGS
- ERR_SOCKET_ALREADY_BOUND
- ERR_SOCKET_DGRAM_IS_CONNECTED
- ERR_SOCKET_DGRAM_NOT_CONNECTED
- ERR_SOCKET_BAD_BUFFER_SIZE
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/d19784c3f9033522.
Report an issue: GitHub.