vectordotdev/vector · error
systemd fd already consumed
Error message
systemd fd already consumed
What it means
Runtime error from `try_bind_udp_socket` in src/sources/util/net/udp.rs. With `SocketListenAddr::SystemdFd(offset)`, the code calls `listenfd.take_udp_socket(offset)`; a `None` result — offset beyond the inherited fds, or the fd already consumed — is returned as `io::Error` (kind `AddrInUse`, message "systemd fd already consumed"). UDP sockets need a matching `ListenDatagram=` systemd unit.
Source
Thrown at src/sources/util/net/udp.rs:17
use std::io;
use listenfd::ListenFd;
use tokio::net::UdpSocket;
use super::SocketListenAddr;
/// Binds a UDP socket to the listen address.
pub async fn try_bind_udp_socket(
addr: SocketListenAddr,
mut listenfd: ListenFd,
) -> io::Result<UdpSocket> {
match addr {
SocketListenAddr::SocketAddr(addr) => UdpSocket::bind(&addr).await,
SocketListenAddr::SystemdFd(offset) => match listenfd.take_udp_socket(offset)? {
Some(socket) => UdpSocket::from_std(socket),
None => Err(io::Error::new(
io::ErrorKind::AddrInUse,
"systemd fd already consumed",
)),
},
}
}
View on GitHub (pinned to 3708c39b12)
Solutions
- Declare a `ListenDatagram=` entry in the `.socket` unit for the UDP source and restart it so the fd is inherited
- Match the fd offsets in Vector config to the order of systemd's passed fds; use one fd per socket
- Outside systemd, bind a concrete address (`address = "0.0.0.0:514"`)
Example fix
# before (unit only had ListenStream=; no datagram fd) [sources.syslog] type = "syslog" address = "systemd" mode = "udp" # after # vector.socket: ListenDatagram=514 [sources.syslog] type = "syslog" address = "systemd" mode = "udp"
Defensive patterns
Strategy: validation
Validate before calling
// Before using SocketListenAddr::SystemdFd for UDP, confirm fds were inherited
fn systemd_fd_count() -> Option<usize> {
let pid_ok = std::env::var("LISTEN_PID").ok()?.parse::<u32>().ok()? == std::process::id();
let fds = std::env::var("LISTEN_FDS").ok()?.parse::<usize>().ok()?;
pid_ok.then_some(fds)
} Try / catch
match try_bind_udp_socket(addr, listenfd).await {
Err(e) if e.kind() == std::io::ErrorKind::AddrInUse && e.to_string().contains("systemd") => {
// no datagram fd at that offset: fix the unit (ListenDatagram=) or bind a real address
}
other => other,
} Prevention
- Declare ListenDatagram= (not ListenStream=) in the .socket unit for UDP sources
- Match fd offsets to the inherited fd order; one fd per socket
- Don't run systemd-bound configs outside systemd; use concrete addresses for manual runs
When it happens
Trigger: A UDP source (e.g. `syslog` or `socket` with mode `udp`) configured with `address = "systemd"` while the systemd unit passes only `ListenStream=` (TCP) fds, passes fewer fds than the offset, the process is not systemd-supervised, or the fd was already taken by another bind.
Common situations: Reusing a TCP socket-activation unit for a UDP source (fd exists but is TCP, or is absent); running Vector directly during debugging while the config keeps `systemd` as the bind address.
Related errors
- systemd fd already consumed
- Multicast for systemd fd sockets is not supported
- Failed to set up SIGINT handler.
- invalid timestamp
- path and query should never fail to parse
AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20).
Data as JSON: /api/errors/8cfc43b9ffad8644.
Report an issue: GitHub.