zeroclaw-labs/zeroclaw · error

ping handshake failed after reconnect on {port_path} — firmw

Error message

ping handshake failed after reconnect on {port_path} — firmware may not be running

What it means

After dropping a stale serial transport, `reconnect` opens a fresh `HardwareSerialTransport` at the default baud and requires a successful ping handshake to prove firmware is alive. A failed handshake bails with the port path. The port opened, but nothing speaking the firmware's ping protocol answered: firmware is missing, crashed, sitting in a bootloader, or the device at that path is something else entirely.

Source

Thrown at crates/zeroclaw-hardware/src/device.rs:508

            None => entry.device.device_path.clone().ok_or_else(|| {
                ::zeroclaw_log::record!(
                    WARN,
                    ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)
                        .with_outcome(::zeroclaw_log::EventOutcome::Failure)
                        .with_attrs(::serde_json::json!({"device_alias": alias})),
                    "device registry reconnect refused: no recorded port path"
                );
                anyhow::Error::msg(format!("device {alias} has no port path"))
            })?,
        };

        // Drop the stale transport.
        entry.transport = None;

        // Create a fresh transport and verify firmware is alive.
        let transport = HardwareSerialTransport::new(&port_path, DEFAULT_BAUD);
        if !transport.ping_handshake().await {
            anyhow::bail!(
                "ping handshake failed after reconnect on {port_path} — \
                 firmware may not be running"
            );
        }

        entry.transport = Some(Arc::new(transport) as Arc<dyn super::transport::Transport>);
        entry.capabilities.gpio = true;

        ::zeroclaw_log::record!(
            INFO,
            ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)
                .with_attrs(::serde_json::json!({"alias": alias, "port": port_path})),
            "device reconnected"
        );
        Ok(())
    }
}

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Flash (or reflash) the ZeroClaw firmware on the device and retry the reconnect
  2. Power-cycle the board and confirm the port path still matches the intended device
  3. Open a serial monitor at the default baud and verify the device responds; if it is silent, firmware is not running
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight before starting work on a device:
let transport = HardwareSerialTransport::new(port_path, DEFAULT_BAUD);
if !transport.ping_handshake().await {
    anyhow::bail!("device on {port_path} is not answering pings — flash firmware first");
}

Try / catch

match device.reconnect().await {
    Err(e) if e.to_string().contains("ping handshake failed") => {
        // Not transient: prompt a reflash, then one manual retry.
        prompt_reflash_firmware(port_path).await?;
        device.reconnect().await?
    }
    other => other?,
}

Prevention

When it happens

Trigger: USB reconnect after a device reset where firmware crashed or was never flashed; a board stuck in bootloader/DFU mode; another USB-serial device enumerating at the same port path after replug.

Common situations: Power brownout or watchdog reset leaving firmware dead; an interrupted flash leaving no application firmware; Linux ttyUSB/ttyACM enumeration shifting between replugs so the path now points at a different device.

Understand the failure class

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/390a0d4c82d06727. Report an issue: GitHub.