FuelLabs/sway · error · anyhow::Error

{}: file not found

Error message

{}: file not found

What it means

parse_bytecode_to_instructions in forc-util fails to File::open the given bytecode file and maps every open error to "<path>: file not found". The underlying io::Error is discarded (map_err(|_| ...)), so permission denied and true missing-file are indistinguishable. This parser feeds get_bytecode_id, used by forc contract-id / forc predicate-root bytecode hashing.

Source

Thrown at forc-util/src/bytecode.rs:54

    fn next(&mut self) -> Option<InstructionWithBytes> {
        let mut buffer = [0; fuel_asm::Instruction::SIZE];
        // Read the next instruction into the buffer
        match self.buf_reader.read_exact(&mut buffer) {
            Ok(_) => fuel_asm::from_bytes(buffer)
                .next()
                .map(|inst| (inst, buffer.to_vec())),
            Err(_) => None,
        }
    }
}

/// Parses a bytecode file into an iterator of instructions and their corresponding bytes.
pub fn parse_bytecode_to_instructions<P>(path: P) -> anyhow::Result<InstructionWithBytesIterator>
where
    P: AsRef<Path> + Clone,
{
    let f = File::open(path.clone())
        .map_err(|_| anyhow!("{}: file not found", path.as_ref().to_string_lossy()))?;
    let buf_reader = BufReader::new(f);

    Ok(InstructionWithBytesIterator::new(buf_reader))
}

/// Gets the bytecode ID from a bytecode file. The bytecode ID is the hash of the bytecode after removing the
/// condigurables section, if any.
pub fn get_bytecode_id<P>(path: P) -> anyhow::Result<String>
where
    P: AsRef<Path> + Clone,
{
    let mut instructions = parse_bytecode_to_instructions(path.clone())?;

    // Collect the first six instructions into a temporary vector
    let mut first_six_instructions = Vec::with_capacity(CONFIGURABLES_OFFSET_PREAMBLE);
    for _ in 0..CONFIGURABLES_OFFSET_PREAMBLE {
        if let Some(instruction) = instructions.next() {
            first_six_instructions.push(instruction);

View on GitHub (pinned to 47e5e902fa)

Solutions

  1. Rebuild the project (`forc build`) and point at the freshly generated .bin under out/debug|release
  2. Verify the path from the directory you actually invoke forc from, or use an absolute path
  3. Check file permissions if the file visibly exists (the message cannot distinguish a permission failure)

Example fix

# before
forc contract-id --bytecode-file out/debug/counter.bin   # renamed package

# after
forc build && forc contract-id --bytecode-file out/debug/my_renamed_pkg.bin
Defensive patterns

Strategy: validation

Validate before calling

let path = std::path::Path::new(bytecode_path);
if !path.is_file() {
    anyhow::bail!("bytecode file '{}' not found or unreadable", path.display());
}
let id = forc_util::bytecode::get_bytecode_id(path)?;

Type guard

fn readable_bin(p: &std::path::Path) -> bool {
    std::fs::metadata(p).map(|m| m.is_file()).unwrap_or(false)
}

Try / catch

match forc_util::bytecode::get_bytecode_id(&path) {
    Ok(id) => Ok(id),
    Err(e) if e.to_string().ends_with("file not found") => {
        Err(anyhow::anyhow!("build the project first: forc build (looked in {})", path.display()))
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Calling get_bytecode_id / parse_bytecode_to_instructions with a wrong, moved, or unreadable path — e.g. `forc contract-id --bytecode-file out/debug/old-name.bin` after the project was renamed, or running from a directory where the relative output path does not resolve.

Common situations: Stale hardcoded paths in scripts after `forc build` output names change (binary named after the package), wrong cwd when invoking forc commands with relative paths, or file permissions blocking read access.

Related errors


AI-assisted analysis of FuelLabs/sway@47e5e902fa (2026-08-16). Data as JSON: /api/errors/823ce4d047b89f23. Report an issue: GitHub.