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

  1. 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.
  2. 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.
  3. If artifacts are produced in parallel, ensure the build step finishes (make/turbo dependency) before loading.
  4. 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

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


AI-assisted analysis of FuelLabs/fuels-rs@d9a250a518 (2026-08-16). Data as JSON: /api/errors/12b0aa5da7ddcc72. Report an issue: GitHub.