zeroclaw-labs/zeroclaw · error
Nucleo firmware not found at {}. Run from zeroclaw repo root
Error message
Nucleo firmware not found at {}. Run from zeroclaw repo root. What it means
flash_nucleo_firmware locates the firmware at <CARGO_MANIFEST_DIR>/firmware/nucleo, where CARGO_MANIFEST_DIR is baked in at compile time from the zeroclaw-hardware crate. This bail fires when that directory has no Cargo.toml. Despite the message saying 'Run from zeroclaw repo root', the path does not depend on the current working directory — changing directories cannot fix it.
Source
Thrown at crates/zeroclaw-hardware/src/peripherals/nucleo_flash.rs:35
.map(|o| o.status.success())
.unwrap_or(false)
}
/// Flash ZeroClaw Nucleo firmware. Builds from firmware/nucleo.
pub fn flash_nucleo_firmware() -> Result<()> {
if !probe_rs_available() {
anyhow::bail!(
"probe-rs not found. Install it:\n cargo install probe-rs-tools --locked\n\n\
Or: curl -LsSf https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.sh | sh\n\n\
Connect Nucleo via USB (ST-Link). Then run this command again."
);
}
// CARGO_MANIFEST_DIR = repo root (zeroclaw's Cargo.toml)
let repo_root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let firmware_dir = repo_root.join("firmware").join("nucleo");
if !firmware_dir.join("Cargo.toml").exists() {
anyhow::bail!(
"Nucleo firmware not found at {}. Run from zeroclaw repo root.",
firmware_dir.display()
);
}
println!("Building ZeroClaw Nucleo firmware...");
let build = Command::new("cargo")
.args(["build", "--release", "--target", TARGET])
.current_dir(&firmware_dir)
.output()
.context("cargo build failed")?;
if !build.status.success() {
let stderr = String::from_utf8_lossy(&build.stderr);
anyhow::bail!("Build failed:\n{}", stderr);
}
let elf_path = firmware_dirView on GitHub (pinned to 88bb9c8533)
Solutions
- Use a full git clone of the zeroclaw repo so firmware/nucleo sits next to crates/zeroclaw-hardware, and run the flash from that checkout
- Verify the path printed in the error contains Cargo.toml; if not, restore the firmware/nucleo directory
- Rebuild zeroclaw inside the full checkout so CARGO_MANIFEST_DIR resolves to it
Defensive patterns
Strategy: validation
Validate before calling
let firmware = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("firmware").join("nucleo");
if !firmware.join("Cargo.toml").exists() {
anyhow::bail!("full zeroclaw checkout required: {} missing", firmware.display());
}
flash_nucleo_firmware()?; Prevention
- Run board flashing only from a full source checkout, never from a copied binary
- Remember the firmware path is compile-time (CARGO_MANIFEST_DIR): moving the repo after build invalidates it
- Document that flashing commands require the repo, not just the runtime
When it happens
Trigger: The zeroclaw binary was built from a source tree lacking firmware/nucleo (sparse checkout, packaged crate build), so the compiled-in absolute path points at a directory that does not exist on this machine.
Common situations: Using a prebuilt/released zeroclaw binary and expecting it to flash firmware; partial clones that exclude the firmware directory; moving or deleting the repo after building.
Related errors
- Bridge app not found at {}. Run from zeroclaw repo root.
- probe-rs not found. Install it: cargo install probe-rs-too
- Build failed:\n{}
- Built binary not found at {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/87e9cdfc58a3ac0e.
Report an issue: GitHub.