stalwartlabs/stalwart · error

Failed to start event collector

Error message

Failed to start event collector

What it means

This panic occurs when the OS fails to spawn the dedicated 'stalwart-collector' thread that runs the event collector loop. `thread::Builder::spawn` returns Err (e.g. resource exhaustion), and the `expect` turns it into a panic during the lazy initialization of the COLLECTOR static.

Source

Thrown at crates/trc/src/ipc/collector.rs:87

const SMTP_CONN_END: usize = EventType::Smtp(SmtpEvent::ConnectionEnd).to_id() as usize;
const MANAGE_SIEVE_CONN_START: usize =
    EventType::ManageSieve(ManageSieveEvent::ConnectionStart).to_id() as usize;
const MANAGE_SIEVE_CONN_END: usize =
    EventType::ManageSieve(ManageSieveEvent::ConnectionEnd).to_id() as usize;
const EV_ATTEMPT_START: usize = EventType::Delivery(DeliveryEvent::AttemptStart).to_id() as usize;
const EV_ATTEMPT_END: usize = EventType::Delivery(DeliveryEvent::AttemptEnd).to_id() as usize;

const STALE_SPAN_CHECK_WATERMARK: usize = 8000;
const SPAN_MAX_HOLD: u64 = 60 * 60 * 24; // 1 day

pub(crate) static COLLECTOR_THREAD: LazyLock<Arc<CollectorThread>> = LazyLock::new(|| {
    Arc::new(
        Builder::new()
            .name("stalwart-collector".to_string())
            .spawn(move || {
                Collector::default().collect();
            })
            .expect("Failed to start event collector"),
    )
});

impl Collector {
    fn collect(&mut self) {
        let mut do_continue = true;

        // Update
        self.update();

        while do_continue {
            match CHANNEL_FLAGS.swap(0, Ordering::Relaxed) {
                0 => {
                    park();
                }
                CHANNEL_UPDATE_MARKER..=u64::MAX => {
                    do_continue = self.update();
                }

View on GitHub (pinned to e962003857)

Solutions

  1. Raise the container/host thread or process limit (ulimit -u, cgroup pids.max) and restart the server
  2. Free thread/memory resources or increase the container memory allocation
  3. Ensure the binary runs in an environment where thread creation is permitted
Defensive patterns

Strategy: try-catch

Try / catch

let handle = Builder::new().name("stalwart-collector".into()).spawn(...)
    .expect("Failed to start event collector");
// before spawning, check resource headroom; treat Err as fatal-with-message:
match Builder::new().name("stalwart-collector".into()).spawn(...) {
    Ok(h) => h,
    Err(e) => { eprintln!("collector spawn failed: {e}"); return; }
}

Prevention

When it happens

Trigger: Thread spawn failure due to hitting the process/thread or memory limits (ulimit -u, cgroup pids.max, out of memory), or an invalid thread builder configuration.

Common situations: Running the server in a tightly constrained container with a low pids limit; running out of available memory; RLIMIT_NPROC reached on busy hosts.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


AI-assisted analysis of stalwartlabs/stalwart@e962003857 (2026-09-06). Data as JSON: /api/errors/a26639a395641ab0. Report an issue: GitHub.