linera-io/linera-protocol · error · std::io::Error

{}: {error}

Error message

{}: {error}

What it means

Bytecode::load_from_file reads the raw bytes of a Wasm module from disk to build a Bytecode value, which linera-client later uses to publish a module to a chain. Any tokio::fs::read failure is re-wrapped into a new std::io::Error that keeps the original ErrorKind but prepends the failing path. You only see this error when the file at the given path cannot be read at all; malformed Wasm content is not detected here.

Source

Thrown at linera-base/src/data_types.rs:1520

pub struct Bytecode {
    /// Bytes of the bytecode.
    #[serde(with = "serde_bytes")]
    #[debug(with = "hex_debug")]
    pub bytes: Vec<u8>,
}

impl Bytecode {
    /// Creates a new [`Bytecode`] instance using the provided `bytes`.
    pub fn new(bytes: Vec<u8>) -> Self {
        Bytecode { bytes }
    }

    /// Loads bytecode from a Wasm module file.
    #[cfg(not(target_arch = "wasm32"))]
    pub async fn load_from_file(path: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
        let path = path.as_ref();
        let bytes = tokio::fs::read(path).await.map_err(|error| {
            std::io::Error::new(error.kind(), format!("{}: {error}", path.display()))
        })?;
        Ok(Bytecode { bytes })
    }

    /// Compresses the [`Bytecode`] into a [`CompressedBytecode`].
    #[cfg(not(target_arch = "wasm32"))]
    pub fn compress(&self) -> CompressedBytecode {
        #[cfg(with_metrics)]
        let _compression_latency = metrics::BYTECODE_COMPRESSION_LATENCY.measure_latency();
        let compressed_bytes_vec = zstd::stream::encode_all(&*self.bytes, 19)
            .expect("Compressing bytes in memory should not fail");

        CompressedBytecode {
            compressed_bytes: Arc::new(compressed_bytes_vec.into_boxed_slice()),
        }
    }

    /// Compresses the [`Bytecode`] into a [`CompressedBytecode`].

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Verify the file exists at the exact path passed: `ls -l <path>`; if missing, build it first with `cargo build --target wasm32-unknown-unknown --release` (or the project's `linera build`) and copy the exact emitted path from the build output.
  2. If the file exists, check it is a regular file with read permission (`file <path>`, `chmod`/`chown` as needed) and that you are running the client from the directory the relative path assumes — or switch to an absolute path.
  3. If building for a different environment, confirm the wasm files were actually produced for wasm32-unknown-unknown (check `target/wasm32-unknown-unknown/release/`) and not overwritten by a native-only build.
  4. In code, pre-check with tokio::fs::metadata / try_exists before loading and fail with a message that includes the build command to run.

Example fix

// before
let bytecode = Bytecode::load_from_file(&path).await?; // io error may be path-less in logs upstream

// after
if !tokio::fs::try_exists(&path).await? {
    anyhow::bail!(
        "bytecode not found at {}: build it first with `cargo build --target wasm32-unknown-unknown --release`",
        path.display()
    );
}
let bytecode = Bytecode::load_from_file(&path).await?;
Defensive patterns

Strategy: try-catch

Validate before calling

async fn bytecode_readable(path: &std::path::Path) -> std::io::Result<()> {
    let meta = tokio::fs::metadata(path).await?;
    if !meta.is_file() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidInput,
            format!("{} is not a regular file", path.display()),
        ));
    }
    Ok(())
}

Try / catch

match Bytecode::load_from_file(&path).await {
    Ok(bc) => bc,
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
        return Err(anyhow::anyhow!(
            "bytecode {} not found; build with `cargo build --target wasm32-unknown-unknown --release` first",
            path.display()
        ));
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling Bytecode::load_from_file(path) (directly, or via ClientContext::publish_module with a --contract/--service path) where path does not exist, points to a directory, lacks read permission, or is unreachable (broken symlink, missing mount, wrong container volume). The error kind is NotFound, IsADirectory, PermissionDenied, etc., mirroring the underlying OS error.

Common situations: Running `linera publish-module` before building the Wasm artifacts, so target/wasm32-unknown-unknown/release/<app>_{contract,service}.wasm does not exist yet; passing a path from target/release (native build) instead of the wasm32 target dir; relative paths resolved from the wrong working directory; CI or Docker runs where the build output is not mounted into the container.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/2a41c061d12b5723. Report an issue: GitHub.