stamparm/maltrail · error
open pcap
Error message
open pcap
What it means
Panic from `.expect("open pcap")` when `capture::Handle::open_offline` fails to open the replay pcap file. The testkit replay path needs a real capture handle over the file, so an unreadable/invalid pcap aborts the test immediately.
Solutions
- Verify the pcap path exists and is readable before calling replay
- Use an absolute path or the repo_root()-based path helper instead of a relative path
- Regenerate the fixture pcap if it was truncated or corrupted
- Check open_offline's Err by matching instead of expect to surface the underlying cause
Example fix
// before
let mut handle = crate::capture::Handle::open_offline(pcap).expect("open pcap");
// after
let mut handle = match crate::capture::Handle::open_offline(pcap) {
Ok(h) => h,
Err(e) => panic!("open pcap {}: {e}", pcap.display()),
}; Defensive patterns
Strategy: validation
Validate before calling
let meta = std::fs::metadata(pcap).expect("pcap fixture missing");
assert!(meta.is_file() && meta.len() >= 24, "not a pcap file: {}", pcap.display()); Try / catch
let mut handle = crate::capture::Handle::open_offline(pcap)
.unwrap_or_else(|e| panic!("open pcap {}: {e}", pcap.display())); Prevention
- Anchor fixture paths with the repo-root helper, never bare relative paths
- Commit and verify pcap fixtures in CI
- Match on open_offline's error to report the underlying cause
When it happens
Trigger: `replay()` called with a path that does not exist, is not readable, or whose contents are not a valid pcap (bad magic, truncated header), causing `open_offline` to return Err.
Common situations: Wrong relative path for the fixture pcap; test fixture not committed or cleaned up by a previous run; a corrupted/hand-edited pcap file; running the test from a working directory other than the one the path assumes.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
AI-assisted analysis of stamparm/maltrail@77cfb06d76 (2026-09-13).
Data as JSON: /api/errors/3a26c1b804a25891.
Report an issue: GitHub.
Appendix: source
Thrown at sensor/src/testkit.rs:194
}
/// Feed one raw packet (`ip_offset` is where the IP header starts).
pub fn feed(&mut self, packet: &[u8], sec: u64, usec: u32, ip_offset: usize) {
process::process_packet(&mut self.state, packet, sec, usec, ip_offset);
}
/// Feed a packet whose IP header starts at offset 0.
pub fn feed_ip(&mut self, packet: &[u8], sec: u64) {
self.feed(packet, sec, 0, 0);
}
/// Replay a pcap file through the real capture handle, DLT resolution and packet path
/// (everything `worker::run` does, minus the thread and the housekeeping timers).
///
/// Returns the number of packets read. `wallclock` selects the Python-3-compatible
/// timestamp substitution.
pub fn replay(&mut self, pcap: &std::path::Path, wallclock: bool) -> usize {
let mut handle = crate::capture::Handle::open_offline(pcap).expect("open pcap");
let datalink = handle.datalink();
let snaplen = self.state.cfg.capture_snaplen;
let mut count = 0usize;
let mut scratch: Vec<u8> = Vec::new();
loop {
match handle.next_packet() {
Ok(Some(captured)) => {
count += 1;
let data: &[u8] = if captured.data.len() > snaplen {
scratch.clear();
scratch.extend_from_slice(&captured.data[..snaplen]);
&scratch
} else {
captured.data
};
let (sec, usec) = if wallclock {
let now =
std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap_or_default();View on GitHub (pinned to 77cfb06d76)