GyulyVGC/sniffnet · critical · CaptureContext::Error

e.to_string()

Error message

e.to_string()

What it means

In CaptureContext::new (src/networking/types/capture_context.rs:24), the first fallible step is CaptureType::from_source(source, pcap_out_path). On Err the enum degrades to CaptureContext::Error(e.to_string()), storing the raw error text for later display (it becomes sniffer.pcap_error shown under the 'An error occurred!' banner). This covers all failures of opening the capture itself: Capture::from_device(...).open()? for live devices and Capture::from_file(...)? for offline pcaps.

Source

Thrown at src/networking/types/capture_context.rs:24

use crate::translations::translations::network_adapter_translation;
use crate::translations::translations_4::capture_file_translation;
use crate::translations::types::language::Language;
use crate::utils::error_logger::{ErrorLogger, Location};
use pcap::{Active, Address, Capture, Device, Error, Packet, Savefile, Stat};
use serde::{Deserialize, Serialize};

pub enum CaptureContext {
    Live(Live),
    LiveWithSavefile(LiveWithSavefile),
    Offline(Offline),
    Error(String),
}

impl CaptureContext {
    pub fn new(source: &CaptureSource, pcap_out_path: Option<&String>, filters: &Filters) -> Self {
        let mut cap_type = match CaptureType::from_source(source, pcap_out_path) {
            Ok(c) => c,
            Err(e) => return Self::Error(e.to_string()),
        };

        // only apply BPF filter if it is active, and return an error if it fails to apply
        if filters.is_some_filter_active()
            && let Err(e) = cap_type.set_bpf(filters.bpf())
        {
            return Self::Error(e.to_string());
        }

        let cap = match cap_type {
            CaptureType::Live(cap) => cap,
            CaptureType::Offline(cap) => return Self::new_offline(cap),
        };

        if let Some(out_path) = pcap_out_path {
            let savefile_res = cap.savefile(out_path);
            match savefile_res {
                Ok(s) => Self::new_live_with_savefile(cap, s),

View on GitHub (pinned to 48b0575dc0)

Solutions

  1. Read the stored error string on the waiting page — pcap messages distinguish 'no such device', 'permissions problem', and invalid file.
  2. For permission errors: run with sudo / grant CAP_NET_RAW (`setcap cap_net_raw+ep $(which sniffnet)`), on Windows run as admin and ensure Npcap with WinPcap-compatible API is installed.
  3. For device errors: reopen the adapter picker and select a currently present adapter; clear the remembered device in settings.
  4. For file errors: verify the path exists and is a real pcap/pcapng (`capinfos file.pcap` or open in Wireshark); fix the path/extension.
  5. If a savefile is also configured, make sure that path is writable too (error 9 fires next otherwise).

Example fix

// before — error text stored and only surfaced in the GUI
let mut cap_type = match CaptureType::from_source(source, pcap_out_path) {
    Ok(c) => c,
    Err(e) => return Self::Error(e.to_string()),
};

// after — classify common root causes before storing the message
let cap_type = match CaptureType::from_source(source, pcap_out_path) {
    Ok(c) => c,
    Err(e) => {
        let hint = if e.to_string().contains("permission") {
            format!("{e} (try running with elevated privileges)")
        } else {
            e.to_string()
        };
        return Self::Error(hint);
    }
};
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight the capture source before building the CaptureContext
fn source_usable(source: &CaptureSource) -> Option<String> {
    match source {
        CaptureSource::Device(dev) => {
            let exists = pcap::Device::list()
                .map(|list| list.iter().any(|d| d.name == dev.name))
                .unwrap_or(false);
            if exists { None } else { Some(format!("device {} not present", dev.name)) }
        }
        CaptureSource::File(f) => std::fs::metadata(&f.path)
            .err()
            .map(|e| format!("pcap file {}: {e}", f.path)),
    }
}

Try / catch

// handle the degraded enum instead of assuming a live capture
let ctx = CaptureContext::new(source, out_path, filters);
let cap = match ctx.consume() {
    (Some(cap), savefile) => cap,
    (None, _) => {
        // ctx was CaptureContext::Error(msg); surface msg and let the user retry
        show_capture_error(get_error_text(&ctx));
        return;
    }
};

Prevention

When it happens

Trigger: Live: opening the selected device with pcap fails — no such device (adapter renamed/removed since the list was built), permission denied opening the capture handle (non-root without CAP_NET_RAW, Windows without Npcap or without admin), device busy. Offline: Capture::from_file fails — file path doesn't exist, isn't a valid pcap/pcapng, or is unreadable. Result: no Capture variant is built; the GUI waiting page shows the stored string.

Common situations: Running Sniffnet without privileges on Linux/macOS; missing Npcap on Windows; adapter unplugged between listing and selection; double-clicking a corrupted/truncated .pcapng as capture source; file with wrong extension content (renamed text file); path with characters the pcap open rejects; stale settings remembering a device name that no longer exists (config_device.rs falls back to a synthetic 'default' device when Device::lookup() fails).

Related errors


AI-assisted analysis of GyulyVGC/sniffnet@48b0575dc0 (2026-08-16). Data as JSON: /api/errors/386e72cfad031c4d. Report an issue: GitHub.