FuelLabs/fuels-rs · error · std::io::Error
failed to read binary: {binary_filepath:?}: {e}
Error message
failed to read binary: {binary_filepath:?}: {e} What it means
Runtime IO error from Contract::load_from in fuels-programs: the contract binary file passed its existence and .bin-extension validation (validate_path_and_extension) but std::fs::read then failed. The original io::ErrorKind is preserved and the message carries the exact path and OS-level cause, so failures here are I/O-level (permissions, race with a deleted file, symlink issues), not 'file not found'.
Source
Thrown at packages/fuels-programs/src/contract/regular.rs:115
pub fn state_root(&self) -> Bytes32 {
self.compute_roots().2
}
fn compute_roots(&self) -> (ContractId, Bytes32, Bytes32) {
compute_contract_id_and_state_root(&self.code(), &self.salt, &self.storage_slots)
}
/// Loads a contract from a binary file. Salt and storage slots are loaded as well, depending on the configuration provided.
pub fn load_from(
binary_filepath: impl AsRef<Path>,
config: LoadConfiguration,
) -> Result<Contract<Regular>> {
let binary_filepath = binary_filepath.as_ref();
validate_path_and_extension(binary_filepath, "bin")?;
let binary = std::fs::read(binary_filepath).map_err(|e| {
std::io::Error::new(
e.kind(),
format!("failed to read binary: {binary_filepath:?}: {e}"),
)
})?;
let storage_slots = super::determine_storage_slots(config.storage, binary_filepath)?;
Ok(Contract {
code: Regular::new(binary, config.configurables),
salt: config.salt,
storage_slots,
})
}
/// Creates a regular contract with the given code, salt, and storage slots.
pub fn regular(
code: Vec<u8>,
salt: Salt,View on GitHub (pinned to d9a250a518)
Solutions
- Check the embedded {e} cause: 'Permission denied (os error 13)' → chmod 644 the file or adjust the running user; 'No such file or directory' → the file vanished between check and read, rebuild artifacts.
- Verify the path points to the actual forc output binary (typically <project>/out/debug/<name>.bin) and that forc build completed before load_from runs.
- If artifacts are produced in parallel, ensure the build step finishes (make/turbo dependency) before loading.
- Retry once after re-running forc build if the artifact was transiently missing.
Example fix
// before
let contract = Contract::load_from("../out/debug/counter.bin", LoadConfiguration::default())?;
// after: validate readability up front with a clear message
let path = std::path::Path::new("../out/debug/counter.bin");
std::fs::File::open(path).with_context(|| format!("cannot open {} — run `forc build` and check permissions", path.display()))?;
let contract = Contract::load_from(path, LoadConfiguration::default())?; Defensive patterns
Strategy: try-catch
Validate before calling
let path = std::path::Path::new(binary_path);
if !path.is_file() {
anyhow::bail!("{path:?} is not a file — run `forc build` first");
}
std::fs::metadata(path).with_context(|| format!("unreadable: {}", path.display()))?;
// extension check mirroring the library's own guard
assert_eq!(path.extension().and_then(|e| e.to_str()), Some("bin"), "expected a .bin file"); Try / catch
match Contract::load_from(&path, cfg) {
Err(e) if e.to_string().contains("failed to read binary") => {
// IO-level failure after existence+extension checks: inspect permissions,
// rebuild artifacts with forc, then retry once
rebuild_with_forc()?;
Contract::load_from(&path, cfg)
}
other => other,
} Prevention
- Run forc build (and wait for completion) before loading binaries in tests/CI.
- Ensure the process user has read permission on out/debug/*.bin artifacts.
- Load from canonical, stable paths (e.g. derived from CARGO_MANIFEST_DIR) rather than relative paths sensitive to cwd.
When it happens
Trigger: Calling Contract::load_from("path/contract.bin", config) where the file exists with the right extension but the process cannot read it: EACCES on restrictive permissions, the file being removed between the existence check and the read, a broken symlink whose target validate_path_and_extension happened to accept, or reading a directory-like special path.
Common situations: CI running as a low-privilege user over files produced by another user's forc build; out/ artifacts cleaned mid-run by a parallel cargo/forc task; files synced from another OS with lost permissions; paths referencing network mounts that became unavailable.
Related errors
- failed to read storage slots from: {storage_path:?}: {e}
- must have exactly one element
- expected name='value'
- missing attribute '{name}'
- Unrecognized command. Expected one of: {msg}
AI-assisted analysis of FuelLabs/fuels-rs@d9a250a518 (2026-08-16).
Data as JSON: /api/errors/12b0aa5da7ddcc72.
Report an issue: GitHub.