stamparm/maltrail · error
create worker log dir
Error message
create worker log dir
What it means
Panic from `.expect("create worker log dir")` when `std::fs::create_dir_all` cannot create the per-worker temporary logs directory under `$TMPDIR/maltrail-worker-<pid>-<n>`. The worker context needs this directory for LOG_DIR before any worker can run.
Solutions
- Check that std::env::temp_dir() is writable and has free space in the failing environment
- Remove any non-directory file occupying the target path
- Clear stale maltrail-worker-* leftovers in TMPDIR
- Run tests with TMPDIR set to a known-writable directory
Defensive patterns
Strategy: validation
Validate before calling
let log_dir = dir.join("logs");
assert!(std::env::temp_dir().is_dir(), "TMPDIR does not exist");
std::fs::create_dir_all(&log_dir).unwrap_or_else(|e| panic!("create worker log dir {}: {e}", log_dir.display())); Try / catch
match std::fs::create_dir_all(&log_dir) {
Ok(_) => {},
Err(e) => panic!("create worker log dir {}: {e}", log_dir.display()),
} Prevention
- Set TMPDIR to a writable directory in CI containers
- Clean stale maltrail-worker-* paths before test runs
- Monitor temp filesystem free space
When it happens
Trigger: `worker_context()` invoked while the temp filesystem is unwritable or full, the computed temp path collides with an existing non-directory file, or the OS temp dir is unwritable (permissions, read-only mount, sandboxed test runner).
Common situations: CI runners with restricted TMPDIR; TMPDIR pointing to a non-writable path; leftover file at the same path after a prior crashed run; disk-full container.
Understand the failure class
Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.
Related errors
AI-assisted analysis of stamparm/maltrail@77cfb06d76 (2026-09-13).
Data as JSON: /api/errors/8a8f96e4c28a01f6.
Report an issue: GitHub.
Appendix: source
Thrown at sensor/src/testkit.rs:301
}
impl Drop for Harness {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.dir);
}
}
/// A `WorkerContext` wired to `registry.slots[id]`, for tests that need to drive the real
/// `worker::run` rather than the packet path alone — worker lifecycle, exit classification and
/// the liveness metrics all live in `run`, not in `process_packet`.
///
/// The temporary directory is deliberately leaked (tests are short-lived and the OS reclaims
/// `TMPDIR`); a `Drop` guard would have to outlive the returned context.
pub fn worker_context(registry: &Arc<crate::metrics::Registry>, id: usize) -> crate::worker::WorkerContext {
let counter = COUNTER.fetch_add(1, Ordering::Relaxed);
let dir = std::env::temp_dir().join(format!("maltrail-worker-{}-{}", std::process::id(), counter));
let log_dir = dir.join("logs");
std::fs::create_dir_all(&log_dir).expect("create worker log dir");
let trails_file = dir.join("trails.csv");
std::fs::write(&trails_file, "").expect("write trails");
let config_file = dir.join("worker.conf");
std::fs::write(
&config_file,
format!(
"MONITOR_INTERFACE any\n\
CAPTURE_BUFFER 1MB\n\
PROCESS_COUNT 1\n\
UPDATE_PERIOD 999999999\n\
DISABLE_CHECK_SUDO true\n\
USE_CONDENSED_STORAGE false\n\
USE_HEURISTICS false\n\
SENSOR_NAME harness\n\
LOG_DIR {}\n\
TRAILS_FILE {}\n",
log_dir.display(),View on GitHub (pinned to 77cfb06d76)