FuelLabs/sway · error · anyhow::Error

Incomplete bytecode

Error message

Incomplete bytecode

What it means

get_bytecode_id requires at least CONFIGURABLES_OFFSET_PREAMBLE = 6 instructions (48 bytes; indices 0..5, with the offset sentinel at indices 4 and 5) in the bytecode file because the Fuel VM preamble embeds the configurables section offset there. If the instruction iterator runs dry before six entries are collected, the file is truncated/empty/not real bytecode and this error returns.

Source

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

    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);
        } else {
            return Err(anyhow!("Incomplete bytecode"));
        }
    }

    let (lo_instr, low_raw) = &first_six_instructions[CONFIGURABLES_OFFSET_INSTR_LO];
    let (hi_instr, hi_raw) = &first_six_instructions[CONFIGURABLES_OFFSET_INSTR_HI];

    if let Err(fuel_asm::InvalidOpcode) = lo_instr {
        if let Err(fuel_asm::InvalidOpcode) = hi_instr {
            // Now assemble the configurables offset.
            let configurables_offset = usize::from_be_bytes([
                low_raw[0], low_raw[1], low_raw[2], low_raw[3], hi_raw[0], hi_raw[1], hi_raw[2],
                hi_raw[3],
            ]);

            // Hash the first six instructions
            let mut hasher = Sha256::new();
            for (_, raw) in first_six_instructions {
                hasher.update(raw);

View on GitHub (pinned to 47e5e902fa)

Solutions

  1. Rebuild with `forc build` and use the newly produced .bin
  2. Confirm the file is the raw bytecode binary (out/debug/<pkg>.bin), not the ABI json, and is at least 48 bytes
  3. If it persists, delete the out/ directory entirely and rebuild from scratch

Example fix

# before
forc contract-id --bytecode-file out/debug/my_pkg-abi.json

# after
forc contract-id --bytecode-file out/debug/my_pkg.bin
Defensive patterns

Strategy: validation

Validate before calling

const MIN_INSTR_BYTES: u64 = 6 * 4; // CONFIGURABLES_OFFSET_PREAMBLE instructions, 4 bytes each
let meta = std::fs::metadata(&bin_path)?;
if meta.len() < MIN_INSTR_BYTES {
    anyhow::bail!("bytecode too small ({} bytes); rebuild with `forc build`", meta.len());
}

Try / catch

let id = match get_bytecode_id(&path) {
    Ok(id) => id,
    Err(e) if e.to_string() == "Incomplete bytecode" => {
        anyhow::bail!("artifact at {} is empty/truncated — rerun `forc build`", path.display())
    }
    Err(e) => return Err(e),
};

Prevention

When it happens

Trigger: Passing an empty or truncated .bin, a non-bytecode file (e.g. a .json ABI file) to get_bytecode_id / `forc contract-id --bytecode-file`, or a build artifact cut short by a full disk or interrupted `forc build`.

Common situations: Confusing the ABI json artifact with the binary artifact in out/debug, partial artifacts left after a cancelled build, or a script globbing *.bin in a directory that contains placeholder files.

Related errors


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