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

failed to load contract bytecode from {contract:?}: {e}

Error message

failed to load contract bytecode from {contract:?}: {e}

What it means

ClientContext::publish_module loads the contract half of an application from the --contract path using Bytecode::load_from_file, re-wrapping any I/O failure with the specific contract path. This is the contract-side twin of the service error at line 860; which one fires tells you which path argument was bad. The error is a plain I/O condition (kind preserved), not a Wasm-validation failure.

Source

Thrown at linera-client/src/client_context.rs:854

            chain_info,
        })
    }
}

#[cfg(feature = "fs")]
impl<Env: Environment> ClientContext<Env> {
    /// Publishes a module from its contract and service bytecode files.
    pub async fn publish_module(
        &mut self,
        chain_client: &ChainClient<Env>,
        contract: PathBuf,
        service: PathBuf,
        vm_runtime: VmRuntime,
        formats: Option<PathBuf>,
    ) -> Result<ModuleId, Error> {
        info!("Loading bytecode files");
        let contract_bytecode = Bytecode::load_from_file(&contract).await.map_err(|e| {
            std::io::Error::new(
                e.kind(),
                format!("failed to load contract bytecode from {contract:?}: {e}"),
            )
        })?;
        let service_bytecode = Bytecode::load_from_file(&service).await.map_err(|e| {
            std::io::Error::new(
                e.kind(),
                format!("failed to load service bytecode from {service:?}: {e}"),
            )
        })?;

        let formats_bytes = match formats {
            Some(path) => Some(bcs::to_bytes(&load_formats_from_snap(&path)?)?),
            None => None,
        };

        info!("Publishing module");
        let (blobs, module_id) = create_bytecode_blobs(

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Check the exact --contract path exists and is a file (`ls -l`); if missing, build the wasm32 artifacts and reuse the path printed by the build step.
  2. Use the artifact from target/wasm32-unknown-unknown/release/, not target/release/, and prefer absolute paths (or run the CLI from the project root) to avoid cwd-relative misses.
  3. If it exists but still fails, fix permissions/ownership or mount the artifact directory into the container/CI environment.

Example fix

# before
linera publish-module --contract contract.wasm --service service.wasm ...
# fails if run from a dir without those files

# after: build first, publish with the real wasm32 target paths
linera publish-module \
  --contract target/wasm32-unknown-unknown/release/my_app_contract.wasm \
  --service  target/wasm32-unknown-unknown/release/my_app_service.wasm ...
Defensive patterns

Strategy: try-catch

Validate before calling

fn artifacts_exist(paths: &[&std::path::Path]) -> anyhow::Result<()> {
    for p in paths {
        let meta = std::fs::metadata(p)
            .with_context(|| format!("missing artifact {}; run the wasm32 build first", p.display()))?;
        anyhow::ensure!(meta.is_file(), "{} is not a file", p.display());
    }
    Ok(())
}

Try / catch

if let Err(e) = context.publish_module(chain_client.clone(), contract, service, vm_runtime, formats).await {
    if e.to_string().contains("failed to load contract bytecode") {
        eprintln!("contract wasm missing — run: cargo build --target wasm32-unknown-unknown --release");
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Calling publish_module (the `linera publish-module --contract <path> --service <path>` flow) where the --contract path is missing, unreadable, a directory, or a dangling symlink. It fires before the service path is read or any chain communication starts.

Common situations: Publishing before `cargo build --target wasm32-unknown-unknown --release` (or `linera build`) produced the contract .wasm; pointing --contract at the native target dir; a typo in the filename; running from the wrong working directory with a relative path; CI artifacts not copied into the job's 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/ce51f6cfdb207726. Report an issue: GitHub.