AprilNEA/OpenLogi · error

the running Agent could not complete the online

Error message

the running Agent could not complete the online {family} semantic read; transient, transport, protocol, timeout, open, and disconnect errors abort capture (no profile was written)

What it means

Raised by `safe_read_error` when a live semantic read (DPI, SmartShift, wheel, or backlight) through the running agent fails for any reason other than an explicit `FeatureUnsupported` reply: RPC timeout, transport/disconnect errors, protocol errors, or device-level open/transient failures. Capture is intentionally fail-closed — any ambiguous read failure aborts so an incorrect profile is never written.

Solutions

  1. Retry the command — transient wireless drops are the most common cause and a retry usually succeeds.
  2. Verify the agent is responsive (open the GUI or `openlogi list`) and restart it if wedged.
  3. Confirm the device stays connected during capture: fresh batteries, close to the receiver, no USB power management suspending the receiver.
  4. If a specific family (e.g. SmartShift) always fails on your device, the feature read may be genuinely unsupported by the firmware — check agent logs for the underlying WriteError and file a device-support issue.

Example fix

// flaky read aborted capture; increase stability and retry
openlogi fixture record profile --id mx --name "MX" --output mx.json
// if transport errors persist
openlogi-agent restart && openlogi fixture record profile --id mx --name "MX" --output mx.json
Defensive patterns

Strategy: retry

Validate before calling

// pre-check the agent is reachable and responsive before capture
tokio::time::timeout(Duration::from_secs(2), client::connect()).await
    .map_err(|_| "agent unresponsive")?;

Try / catch

// retry transient read failures once before giving up
match semantic_read("DPI", client.read_dpi(...)).await {
    Err(e) if e.to_string().contains("semantic read") => semantic_read("DPI", client.read_dpi(...)).await,
    other => other,
}

Prevention

When it happens

Trigger: `semantic_read` observes: the 5-second `READ_TIMEOUT` elapsing; a tarpc `RpcError` (agent disconnected); `Err(_)` from the agent that is not `WriteError::FeatureUnsupported` — e.g. `WriteError::Transport`, timeout, open failure, or disconnect while reading DPI/SmartShift/wheel/backlight.

Common situations: Device drops mid-read (wireless interference, sleep); agent busy or wedged so the RPC times out; HID++ protocol error on a quirky device; user unplugs the device while the profile is being recorded.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of AprilNEA/OpenLogi@e846e6f4b4 (2026-09-13). Data as JSON: /api/errors/e946d5c90350e63f. Report an issue: GitHub.

Appendix: source

Thrown at crates/openlogi-cli/src/cmd/fixture/record_profile.rs:370

}

async fn semantic_read<T>(
    family: &'static str,
    request: impl Future<Output = Result<Result<T, WriteError>, RpcError>>,
) -> Result<ProfileSetting<T>> {
    let result = tokio::time::timeout(READ_TIMEOUT, request)
        .await
        .map_err(|_| safe_read_error(family))?
        .map_err(|_| safe_read_error(family))?;
    match result {
        Ok(value) => Ok(ProfileSetting::Supported(value)),
        Err(WriteError::FeatureUnsupported { .. }) => Ok(ProfileSetting::Unsupported),
        Err(_) => Err(safe_read_error(family)),
    }
}

fn safe_read_error(family: &str) -> anyhow::Error {
    anyhow!(
        "the running Agent could not complete the online {family} semantic read; transient, \
         transport, protocol, timeout, open, and disconnect errors abort capture (no profile was \
         written)"
    )
}

fn capture_standalone(source: &StandaloneDevice) -> Result<ProfileCaptureParts> {
    let mut retained = source.clone();
    sanitize::standalone(&mut retained)?;
    let route = selection::standalone_route(&retained);
    let light_supported = retained.light_capabilities.is_some_and(|capabilities| {
        capabilities.power
            || capabilities.brightness.is_some()
            || capabilities.temperature.is_some()
    });
    let settings = ProfileDeviceSettings {
        route: route.clone(),
        dpi: ProfileSetting::Unsupported,

View on GitHub (pinned to e846e6f4b4)