stamparm/maltrail · error
create log dir
Error message
create log dir
What it means
Right after creating the harness directory, with_options_in() creates the logs subdirectory (or uses the shared log dir) with std::fs::create_dir_all and panics with "create log dir" on failure. When a shared_log_dir is supplied, that pre-existing path must be writable; otherwise the fresh harness dir's logs/ must be creatable.
Solutions
- Verify the shared_log_dir path exists, is a directory, and is writable before calling with_options_in
- Pass None to let the harness manage its own logs subdirectory if the shared path is unreliable
- Check disk space and permissions on the temp filesystem
- Include the log_dir path and io::Error in the panic message
Example fix
// before
std::fs::create_dir_all(&log_dir).expect("create log dir");
// after
std::fs::create_dir_all(&log_dir)
.unwrap_or_else(|e| panic!("create log dir {}: {e}", log_dir.display())); Defensive patterns
Strategy: validation
Validate before calling
if let Some(p) = shared_log_dir { assert!(p.is_dir() && p.metadata().map(|m| m.permissions().writable()).unwrap_or(false), "shared_log_dir {} not a writable dir", p.display()); } Type guard
fn usable_log_dir(p: &std::path::Path) -> bool { p.is_dir() && p.metadata().map(|m| m.permissions().writable()).unwrap_or(false) } Try / catch
std::fs::create_dir_all(&log_dir).unwrap_or_else(|e| panic!("create log dir {}: {e}", log_dir.display())); Prevention
- Pass only existing writable directories as shared_log_dir
- Prefer harness-managed logs (None) unless sharing is required
- Verify the shared dir survives the whole test run
When it happens
Trigger: Calling Harness::with_options_in() where dir.join("logs") cannot be created (filesystem error), or the provided shared_log_dir path does not exist and cannot be created (bad path, permissions, disk full).
Common situations: Passing a shared_log_dir pointing at a file instead of a directory or an unwritable path; read-only test volume; race where another process deleted the shared log dir between calls.
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/7f27fdce76be32e2.
Report an issue: GitHub.
Appendix: source
Thrown at sensor/src/testkit.rs:96
pub fn with_options(trails: &[(&str, &str, &str)], options: HarnessOptions) -> Harness {
Harness::with_options_in(trails, options, None)
}
fn with_options_in(
trails: &[(&str, &str, &str)],
options: HarnessOptions,
shared_log_dir: Option<&std::path::Path>,
) -> Harness {
let id = COUNTER.fetch_add(1, Ordering::Relaxed);
let dir = std::env::temp_dir().join(format!("maltrail-harness-{}-{}", std::process::id(), id));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).expect("create harness dir");
let log_dir = match shared_log_dir {
Some(p) => p.to_path_buf(),
None => dir.join("logs"),
};
std::fs::create_dir_all(&log_dir).expect("create log dir");
let trails_file = dir.join("trails.csv");
std::fs::write(&trails_file, "").expect("write trails");
let root = repo_root();
let config_file = dir.join("harness.conf");
let mut config_text = 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\
SENSOR_NAME harness\n\
SCAN_WINDOW 30\n\
USE_HEURISTICS {}\n\
CHECK_HOST_DOMAINS {}\n\
CHECK_MISSING_HOST {}\n\View on GitHub (pinned to 77cfb06d76)