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

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

Error message

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

What it means

ClientContext::publish_module loads the service half of an application from the --service path using Bytecode::load_from_file; this branch re-wraps the I/O failure with the specific service path. It only runs after the contract bytecode loaded successfully, so seeing this error means --contract was fine and --service was not. Like its contract twin, it preserves the underlying io::ErrorKind.

Source

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

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(
            contract_bytecode,
            service_bytecode,
            vm_runtime,
            formats_bytes,
        )
        .await;

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Verify the exact --service path exists (`ls -l`); confirm the service artifact name matches the crate (<crate>_service.wasm) under target/wasm32-unknown-unknown/release/.
  2. Rebuild both artifacts together (cargo build --target wasm32-unknown-unknown --release or `linera build`) so contract and service stay in sync, then republish with both fresh paths.
  3. Check permissions/mounts if the file is present in the builder but absent in the runtime environment.

Example fix

# before
linera publish-module \
  --contract target/wasm32-unknown-unknown/release/my_app_contract.wasm \
  --service  target/wasm32-unknown-unknown/release/my_app.wasm ...   # wrong name -> this error

# after
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

let (contract, service) = (contract_path.as_path(), service_path.as_path());
for p in [contract, service] {
    if !p.is_file() {
        anyhow::bail!("artifact {} not found; build both wasm modules first", p.display());
    }
}

Try / catch

match context.publish_module(chain_client.clone(), contract, service, vm_runtime, formats).await {
    Ok(id) => id,
    Err(e) if e.to_string().contains("failed to load service bytecode") => {
        anyhow::bail!("service wasm at {service:?} missing — rebuild both artifacts and retry")
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling publish_module where the --service path is missing, unreadable, or a directory — typically because the service .wasm was never built or has a different filename than the contract artifact (e.g. <app>_service.wasm vs <app>_contract.wasm) and the wrong name was passed.

Common situations: The contract artifact exists but the service artifact was skipped (partial build, cleaned target, feature-gated service crate not built); filename typo (missing _service suffix); renaming the crate without updating the publish command; copying only one artifact into a Docker/CI stage.

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/c2bd1170ef0509cd. Report an issue: GitHub.