vectordotdev/vector · critical
Failed to bind to listener socket at path: {}. Err: {}
Error message
Failed to bind to listener socket at path: {}. Err: {} What it means
Unix-stream sources (socket sources configured with a filesystem path) bind a tokio UnixListener at startup and panic if bind() fails, printing the path and the io::Error. Because the bind happens inside the spawned source future, the failure is fatal for the run: the process aborts instead of silently running without the source.
Source
Thrown at src/sources/util/unix_stream.rs:54
/// Passing in different functions for `decoder` and `handle_events` can allow
/// for different source-specific logic (such as decoding syslog messages in the
/// syslog source).
pub fn build_unix_stream_source<D, F, E>(
listen_path: PathBuf,
socket_file_mode: Option<u32>,
decoder: D,
handle_events: impl Fn(&mut [Event], Option<Bytes>) + Clone + Send + Sync + 'static,
shutdown: ShutdownSignal,
out: SourceSender,
) -> crate::Result<Source>
where
D: tokio_util::codec::Decoder<Item = (F, usize), Error = E> + Clone + Send + 'static,
E: StreamDecodingError + std::fmt::Display + Send + From<std::io::Error>,
F: Into<SmallVec<[Event; 1]>> + Send,
{
Ok(Box::pin(async move {
let listener = UnixListener::bind(&listen_path).unwrap_or_else(|e| {
panic!(
"Failed to bind to listener socket at path: {}. Err: {}",
listen_path.to_string_lossy(),
e
)
});
info!(message = "Listening.", path = ?listen_path, r#type = "unix");
change_socket_permissions(&listen_path, socket_file_mode)
.expect("Failed to set socket permissions");
let bytes_received = register!(BytesReceived::from(Protocol::UNIX));
let connection_open = OpenGauge::new();
let stream = UnixListenerStream::new(listener).take_until(shutdown.clone());
tokio::pin!(stream);
while let Some(socket) = stream.next().await {
let socket = match socket {
Err(error) => {View on GitHub (pinned to 3708c39b12)
Solutions
- Remove the stale socket before start: rm -f <path> (systemd ExecStartPre=-/usr/bin/rm -f <path> works well)
- Shorten the path and ensure its directory exists and is writable by the Vector user
- Ensure exactly one Vector instance uses the path: lsof <path> or ss -x | grep <path>
- If a supervisor restarts Vector, add pre-stop cleanup so stop/start cycles don't leak the socket
Example fix
# before (systemd unit) [Service] ExecStart=/usr/bin/vector --config /etc/vector/vector.toml # after [Service] ExecStartPre=-/usr/bin/rm -f /var/run/vector/vector.sock ExecStart=/usr/bin/vector --config /etc/vector/vector.toml
Defensive patterns
Strategy: validation
Validate before calling
# Pre-start check (shell):
if [ -S "$SOCK" ]; then rm -f "$SOCK" || exit 1; fi
mkdir -p "$(dirname "$SOCK")" && [ -w "$(dirname "$SOCK")" ] || exit 1
// Rust (embedding): probe before the source runs
if listen_path.exists() { std::fs::remove_file(&listen_path)?; }
std::fs::create_dir_all(listen_path.parent().unwrap())?; Prevention
- Clean socket paths in ExecStartPre/pre-stop hooks
- Keep socket paths short and under a directory owned by the Vector user
- Monitor for duplicate Vector processes binding the same socket
When it happens
Trigger: A stale socket file already exists at the path (previous Vector killed uncleanly); the parent directory does not exist or lacks write permission for the Vector user; the path exceeds the OS unix-socket address limit (~108 chars for sun_path on Linux).
Common situations: Restarting after a crash without cleanup; running under a different user than the socket directory owner; a second Vector instance already bound to the same path; long confined paths in containers and /run vs /var/run symlink confusion.
Related errors
- registered log schema required
- MessageStream never calls Ready(None)
- MessageStream never returns Ready(None)
- No timeout is configured for this source.
- Encountered a connection-time error during runtime: {:?}
AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20).
Data as JSON: /api/errors/d1cc309763aa2e68.
Report an issue: GitHub.