{"record":{"id":"d908ee7fb09c564b","repo":"zeroclaw-labs/zeroclaw","slug":"upload-failed-ensure-the-board-is-connected-a","errorCode":null,"errorMessage":"Upload failed:\n{}\n\nEnsure the board is connected and the port is correct (e.g. /dev/cu.usbmodem* on macOS).","messagePattern":"Upload failed:\n(.+?)\n\nEnsure the board is connected and the port is correct \\(e\\.g\\. /dev/cu\\.usbmodem\\* on macOS\\)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-hardware/src/peripherals/arduino_flash.rs","lineNumber":132,"sourceCode":"\n    if !compile.status.success() {\n        let stderr = String::from_utf8_lossy(&compile.stderr);\n        let _ = std::fs::remove_dir_all(&temp_dir);\n        anyhow::bail!(\"Compile failed:\\n{}\", stderr);\n    }\n\n    // Upload\n    println!(\"Uploading to {}...\", port);\n    let upload = Command::new(\"arduino-cli\")\n        .args([\"upload\", \"-p\", port, \"--fqbn\", FQBN, &*sketch_path])\n        .output()\n        .context(\"arduino-cli upload failed\")?;\n\n    let _ = std::fs::remove_dir_all(&temp_dir);\n\n    if !upload.status.success() {\n        let stderr = String::from_utf8_lossy(&upload.stderr);\n        anyhow::bail!(\n            \"Upload failed:\\n{}\\n\\nEnsure the board is connected and the port is correct (e.g. /dev/cu.usbmodem* on macOS).\",\n            stderr\n        );\n    }\n\n    println!(\"ZeroClaw firmware flashed successfully.\");\n    println!(\"The Arduino now supports: capabilities, gpio_read, gpio_write.\");\n    Ok(())\n}\n\n/// Resolve port from config or path. Returns the path to use for flashing.\npub fn resolve_port(\n    config: &zeroclaw_config::schema::Config,\n    path_override: Option<&str>,\n) -> Option<String> {\n    if let Some(p) = path_override {\n        return Some(p.to_string());\n    }","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-hardware/src/peripherals/arduino_flash.rs#L114-L150","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\n[[peripherals.boards]]\nboard = \"arduino-uno\"\ntransport = \"serial\"\npath = \"/dev/ttyUSB0\"\n\n# after (port reported by `arduino-cli board list`)\n[[peripherals.boards]]\nboard = \"arduino-uno\"\ntransport = \"serial\"\npath = \"/dev/ttyACM0\"","handlingStrategy":"validation","validationCode":"// port must exist and be a char device (unix) before uploading\nlet meta = std::fs::metadata(port)\n    .map_err(|_| anyhow::anyhow!(\"port {port} does not exist; check `arduino-cli board list`\"))?;\n#[cfg(unix)]\nassert!(use std::os::unix::fs::FileTypeExt::is_char_device(&meta.file_type()));\nflash_arduino_firmware(port)?;","typeGuard":null,"tryCatchPattern":"match flash_arduino_firmware(port) {\n    Err(e) if format!(\"{e}\").contains(\"Upload failed\") => {\n        // embedded stderr + hint: wrong port, busy port, or permissions;\n        // re-run `arduino-cli board list`, close port holders, check dialout group\n    }\n    rest => rest,\n}","preventionTips":["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"],"tags":["arduino","upload","avrdude","serial-port","hardware-flashing"],"backgroundTag":"firmware-upload-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}