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
- Raise the container/host thread or process limit (ulimit -u, cgroup pids.max) and restart the server
- Free thread/memory resources or increase the container memory allocation
- 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
- Set adequate ulimit -u / cgroup pids.max in containers
- Monitor thread counts and memory on production hosts
- Keep thread creation failures fatal-but-informative rather than silent
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
- Node id {node_id} exceeds {MAX_NODE_ID}, panicking to avoid
- Invalid system time, panicking to avoid data corruption
- failed to install aws-lc-rs as the default rustls crypto pro
- Missing span ID
AI-assisted analysis of stalwartlabs/stalwart@e962003857 (2026-09-06).
Data as JSON: /api/errors/a26639a395641ab0.
Report an issue: GitHub.