zeroclaw-labs/zeroclaw · error
Upload failed: {} Ensure the board is connected and the por
Error message
Upload failed:
{}
Ensure the board is connected and the port is correct (e.g. /dev/cu.usbmodem* on macOS). What it means
flash_arduino_firmware uploads with `arduino-cli upload -p <port> --fqbn arduino:avr:uno`. This bail fires when the upload exits non-zero; arduino-cli/avrdude stderr is embedded plus a hint about board connection and port naming. The port comes from your argument or from resolve_port() (the path configured on the arduino-uno serial board).
Source
Thrown at crates/zeroclaw-hardware/src/peripherals/arduino_flash.rs:132
if !compile.status.success() {
let stderr = String::from_utf8_lossy(&compile.stderr);
let _ = std::fs::remove_dir_all(&temp_dir);
anyhow::bail!("Compile failed:\n{}", stderr);
}
// Upload
println!("Uploading to {}...", port);
let upload = Command::new("arduino-cli")
.args(["upload", "-p", port, "--fqbn", FQBN, &*sketch_path])
.output()
.context("arduino-cli upload failed")?;
let _ = std::fs::remove_dir_all(&temp_dir);
if !upload.status.success() {
let stderr = String::from_utf8_lossy(&upload.stderr);
anyhow::bail!(
"Upload failed:\n{}\n\nEnsure the board is connected and the port is correct (e.g. /dev/cu.usbmodem* on macOS).",
stderr
);
}
println!("ZeroClaw firmware flashed successfully.");
println!("The Arduino now supports: capabilities, gpio_read, gpio_write.");
Ok(())
}
/// Resolve port from config or path. Returns the path to use for flashing.
pub fn resolve_port(
config: &zeroclaw_config::schema::Config,
path_override: Option<&str>,
) -> Option<String> {
if let Some(p) = path_override {
return Some(p.to_string());
}View on GitHub (pinned to 88bb9c8533)
Solutions
- Run `arduino-cli board list` (replug the board if needed) and pass the port it reports
- Close every program holding the port (Arduino IDE serial monitor, screen, the running zeroclaw runtime) and retry
- On Linux, fix permissions: `sudo usermod -aG dialout $USER` then log out and back in
- Read the embedded stderr: 'device not responding' means wrong port/board, 'permission denied' means OS access
- Use OS-correct naming: /dev/cu.usbmodem* on macOS, /dev/ttyACM* on Linux, COM* on Windows
Example fix
# before [[peripherals.boards]] board = "arduino-uno" transport = "serial" path = "/dev/ttyUSB0" # after (port reported by `arduino-cli board list`) [[peripherals.boards]] board = "arduino-uno" transport = "serial" path = "/dev/ttyACM0"
Defensive patterns
Strategy: validation
Validate before calling
// port must exist and be a char device (unix) before uploading
let meta = std::fs::metadata(port)
.map_err(|_| anyhow::anyhow!("port {port} does not exist; check `arduino-cli board list`"))?;
#[cfg(unix)]
assert!(use std::os::unix::fs::FileTypeExt::is_char_device(&meta.file_type()));
flash_arduino_firmware(port)?; Try / catch
match flash_arduino_firmware(port) {
Err(e) if format!("{e}").contains("Upload failed") => {
// embedded stderr + hint: wrong port, busy port, or permissions;
// re-run `arduino-cli board list`, close port holders, check dialout group
}
rest => rest,
} Prevention
- Resolve the port dynamically from `arduino-cli board list` instead of hardcoding it
- Stop the zeroclaw runtime (and any serial monitor) before flashing
- On Linux, keep your user in the dialout group
When it happens
Trigger: Uploading to a port that does not exist or is not the board (/dev/ttyUSB1 vs actual /dev/ttyACM0, wrong COM number), the board being unplugged, the port held open by another program (Arduino IDE serial monitor, screen, an already-running zeroclaw SerialPeripheral), or the OS user lacking permission on the device node.
Common situations: Device name changed after replug; Linux user not in the dialout group (avrdude: permission denied); flashing while the runtime already holds the port open; using /dev/tty.* naming on Linux or vice versa.
Related errors
- Compile failed: {}
- Lark/Feishu marker target is empty
- Lark/Feishu marker target is not a file
- Telegram sendDocument failed: {err}
- Telegram sendPhoto failed: {err}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/d908ee7fb09c564b.
Report an issue: GitHub.