stamparm/maltrail · error
write trails
Error message
write trails
What it means
with_options_in() seeds the harness with an empty trails.csv using std::fs::write and panics with "write trails" on failure. The directory was just created by the harness, so failure points to filesystem-level problems (permissions, disk full, path issues) rather than a missing parent directory.
Solutions
- Check free space and writability of std::env::temp_dir()
- Remove stale maltrail-harness-* directories and rerun
- Avoid external processes cleaning temp files mid-test; use a dedicated TMPDIR for the test run
- Include the file path and io::Error in the panic message
Example fix
// before
std::fs::write(&trails_file, "").expect("write trails");
// after
std::fs::write(&trails_file, "")
.unwrap_or_else(|e| panic!("write trails {}: {e}", trails_file.display())); Defensive patterns
Strategy: try-catch
Validate before calling
assert!(dir.metadata().map(|m| m.permissions().writable()).unwrap_or(false), "harness dir {} not writable", dir.display()); Try / catch
std::fs::write(&trails_file, "").unwrap_or_else(|e| panic!("write trails {}: {e}", trails_file.display())); Prevention
- Check temp filesystem free space before large test runs
- Prevent external temp cleaners from racing tests
- Use a dedicated TMPDIR per CI job
When it happens
Trigger: Calling Harness::with_options_in() when writing dir/trails.csv fails — read-only filesystem, disk quota exceeded, or the harness dir was concurrently deleted.
Common situations: Disk-full CI runners; tests executing on a read-only mount; security software deleting/quarantining files in temp dirs; pid-collision harness dirs owned by another user.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
AI-assisted analysis of stamparm/maltrail@77cfb06d76 (2026-09-13).
Data as JSON: /api/errors/f6182b3e511bfd26.
Report an issue: GitHub.
Appendix: source
Thrown at sensor/src/testkit.rs:99
}
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\
LOG_DIR {}\n\
TRAILS_FILE {}\n",
options.use_heuristics,View on GitHub (pinned to 77cfb06d76)