Error Types

nmrs uses a single error enum, ConnectionError, for all operations. It implements std::error::Error, Display, and Debug.

ConnectionError

#![allow(unused)]
fn main() {
#[non_exhaustive]
pub enum ConnectionError {
    // D-Bus errors
    Dbus(zbus::Error),
    DbusOperation { context: String, source: zbus::Error },

    // Network not found
    NotFound,

    // Authentication
    AuthFailed,
    MissingPassword,
    SupplicantConfigFailed,
    SupplicantTimeout,

    // Connection lifecycle
    DhcpFailed,
    Timeout,
    Stuck(String),

    // Device errors
    NoWifiDevice,
    NoWiredDevice,
    WifiNotReady,
    NoBluetoothDevice,
    NoSavedConnection,

    // Device/activation failures with reason codes
    DeviceFailed(StateReason),
    ActivationFailed(ConnectionStateReason),

    // VPN errors
    NoVpnConnection,
    VpnFailed(String),
    InvalidPrivateKey(String),
    InvalidPublicKey(String),
    InvalidAddress(String),
    InvalidGateway(String),
    InvalidPeers(String),

    // Other
    InvalidUtf8(Utf8Error),
}
}

Error Categories

User-Facing Errors

These indicate issues the user can fix:

ErrorUser Action
NotFoundMove closer to the network or check SSID spelling
AuthFailedCheck password or credentials
MissingPasswordProvide a non-empty password
TimeoutRetry or increase timeout
DhcpFailedCheck network infrastructure
NoWifiDeviceCheck that a Wi-Fi adapter is installed
NoWiredDeviceCheck that an Ethernet adapter exists

Validation Errors

These indicate invalid input to nmrs:

ErrorFix
InvalidPrivateKeyCheck WireGuard key format (base64, ~44 chars)
InvalidPublicKeyCheck peer public key format
InvalidAddressUse CIDR notation (e.g., 10.0.0.2/24)
InvalidGatewayUse host:port format
InvalidPeersAdd at least one peer with allowed IPs

System Errors

These indicate infrastructure issues:

ErrorInvestigation
DbusIs NetworkManager running? Is D-Bus accessible?
DbusOperationCheck context for what operation failed
SupplicantConfigFailedCheck wpa_supplicant configuration
SupplicantTimeoutCheck RADIUS server connectivity
WifiNotReadyWi-Fi device still initializing
StuckNetworkManager in unexpected state
DeviceFailedCheck the StateReason for details
ActivationFailedCheck the ConnectionStateReason for details

StateReason

Low-level device state reason codes from NetworkManager. Used in DeviceFailed:

Common values include reasons like "supplicant disconnect", "DHCP failure", "firmware missing", "carrier dropped", and many others. These map directly to NetworkManager's NM_DEVICE_STATE_REASON_* constants.

ConnectionStateReason

Activation/deactivation reason codes. Used in ActivationFailed:

Common values include reasons like "user disconnected", "carrier dropped", "connection removed", "dependency failed", and others. These map to NetworkManager's NM_ACTIVE_CONNECTION_STATE_REASON_* constants.

ActiveConnectionState

The lifecycle state of an active connection:

#![allow(unused)]
fn main() {
pub enum ActiveConnectionState {
    Unknown,
    Activating,
    Activated,
    Deactivating,
    Deactivated,
    Other(u32),
}
}

Error Handling Patterns

Simple Propagation

#![allow(unused)]
fn main() {
async fn connect() -> nmrs::Result<()> {
    let nm = NetworkManager::new().await?;
    nm.connect("MyWiFi", WifiSecurity::Open).await?;
    Ok(())
}
}

Specific Error Handling

#![allow(unused)]
fn main() {
match nm.connect("MyWiFi", security).await {
    Ok(_) => println!("Connected"),
    Err(ConnectionError::AuthFailed) => eprintln!("Wrong password"),
    Err(ConnectionError::NotFound) => eprintln!("Network not found"),
    Err(e) => eprintln!("Error: {}", e),
}
}

With anyhow

#![allow(unused)]
fn main() {
use anyhow::{Context, Result};

async fn connect() -> Result<()> {
    let nm = NetworkManager::new().await
        .context("Failed to connect to NetworkManager")?;
    nm.connect("MyWiFi", WifiSecurity::Open).await
        .context("Failed to connect to MyWiFi")?;
    Ok(())
}
}

Full API Reference

See docs.rs/nmrs for complete error documentation.