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

  1. Check free space and writability of std::env::temp_dir()
  2. Remove stale maltrail-harness-* directories and rerun
  3. Avoid external processes cleaning temp files mid-test; use a dedicated TMPDIR for the test run
  4. 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

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)