vectordotdev/vector · error

Failed to set up SIGTERM handler.

Error message

Failed to set up SIGTERM handler.

What it means

Vector registers a SIGTERM handler via tokio::signal::unix::signal(SignalKind::terminate()) and unwraps the io::Result with expect. Registration can fail if the environment forbids or exhausts signal-handler setup (sandboxed containers, fd/handler limits, many embedded runtimes), and then the process panics at startup instead of accepting SIGTERM for graceful shutdown.

Source

Thrown at src/signal.rs:198

    /// Shutdown active signal handlers.
    pub fn clear(&mut self) {
        for shutdown_tx in self.shutdown_txs.drain(..) {
            // An error just means the channel was already shut down; safe to ignore.
            _ = shutdown_tx.send(());
        }
    }
}

/// Signals from OS/user.
#[cfg(unix)]
fn os_signals(runtime: &Runtime) -> impl Stream<Item = SignalTo> + use<> {
    use tokio::signal::unix::{SignalKind, signal};

    // The `signal` function must be run within the context of a Tokio runtime.
    runtime.block_on(async {
        let mut sigint = signal(SignalKind::interrupt()).expect("Failed to set up SIGINT handler.");
        let mut sigterm =
            signal(SignalKind::terminate()).expect("Failed to set up SIGTERM handler.");
        let mut sigquit = signal(SignalKind::quit()).expect("Failed to set up SIGQUIT handler.");
        let mut sighup = signal(SignalKind::hangup()).expect("Failed to set up SIGHUP handler.");

        async_stream::stream! {
            loop {
                let signal = tokio::select! {
                    _ = sigint.recv() => {
                        info!(message = "Signal received.", signal = "SIGINT");
                        SignalTo::Shutdown(None)
                    },
                    _ = sigterm.recv() => {
                        info!(message = "Signal received.", signal = "SIGTERM");
                        SignalTo::Shutdown(None)
                    } ,
                    _ = sigquit.recv() => {
                        info!(message = "Signal received.", signal = "SIGQUIT");
                        SignalTo::Quit
                    },

View on GitHub (pinned to 3708c39b12)

Solutions

  1. Use the default container seccomp profile or add rt_sigaction/signalfd to the allowlist
  2. Raise RLIMIT_NOFILE (ulimit -n 65536; LimitNOFILE= in the unit)
  3. In embedding scenarios, register signal handling once and share the stream instead of per-runtime registration
  4. Verify outside the sandbox to confirm the environment is the cause
Defensive patterns

Strategy: validation

Validate before calling

# preflight: signal syscalls available and fds available
ulimit -n
vector validate /etc/vector/vector.toml && vector --config /etc/vector/vector.toml

Prevention

When it happens

Trigger: Starting Vector where SIGTERM registration fails: seccomp/apparmor denying sigaction or signalfd, RLIMIT_NOFILE exhausted, or a test/binary embedding Vector that already registered the maximum number of handlers.

Common situations: Kubernetes nodes with custom seccomp profiles; minimal distroless/scratch images run under strict LSM policies; repeated runtime creation in integration tests.

Related errors


AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20). Data as JSON: /api/errors/9f76a41b31017372. Report an issue: GitHub.