linera-io/linera-protocol · error

{}: got non-zero error code {}

Error message

{}: got non-zero error code {}

What it means

CommandExt::spawn_and_wait_for_stdout pipes stdout, inherits stderr, spawns the child process, and after wait_with_output checks output.status.success(). A non-zero exit code (including death by signal, reported as exit code 128+N on Unix) fails the ensure!, prefixed with 'While executing {:?}' describing the command. The child's own diagnostics went to inherited stderr, so the reason is visible in the surrounding log, not in this error.

Source

Thrown at linera-base/src/command.rs:164

    fn spawn_into(&mut self) -> anyhow::Result<tokio::process::Child> {
        self.kill_on_drop(true);
        debug!("Spawning {:?}", self);
        let child = tokio::process::Command::spawn(self).with_context(|| self.description())?;
        Ok(child)
    }

    async fn spawn_and_wait_for_stdout(&mut self) -> anyhow::Result<String> {
        debug!("Spawning and waiting for {:?}", self);
        self.stdout(Stdio::piped());
        self.stderr(Stdio::inherit());
        self.kill_on_drop(true);

        let child = self.spawn().with_context(|| self.description())?;
        let output = child
            .wait_with_output()
            .await
            .with_context(|| self.description())?;
        ensure!(
            output.status.success(),
            "{}: got non-zero error code {}",
            self.description(),
            output.status,
        );
        String::from_utf8(output.stdout).with_context(|| self.description())
    }

    async fn spawn_and_wait(&mut self) -> anyhow::Result<()> {
        debug!("Spawning and waiting for {:?}", self);
        self.kill_on_drop(true);

        let mut child = self.spawn().with_context(|| self.description())?;
        let status = child.wait().await.with_context(|| self.description())?;
        ensure!(
            status.success(),
            "{}: got non-zero error code {}",
            self.description(),

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Read the child's stderr directly above this error in the log — it contains the actual failure cause
  2. Re-run the failing subcommand manually with the same arguments to reproduce (the {:?} command description in the message shows program and args)
  3. For test-harness failures, clean stale state: kill leftover processes and remove the temporary DB/wallet dirs
  4. If the binary panicked, rebuild (cargo build) and confirm versions match between spawner and child

Example fix

// before
let stdout = cmd.spawn_and_wait_for_stdout().await?; // exit code 1, cause hidden

// after (capture stderr so the cause travels with the error)
let out = cmd.output().await?;
if !out.status.success() {
    anyhow::bail!(
        "command failed ({}): {}",
        out.status,
        String::from_utf8_lossy(&out.stderr)
    );
}
Defensive patterns

Strategy: try-catch

Try / catch

match cmd.spawn_and_wait_for_stdout().await {
    Ok(stdout) => stdout,
    Err(e) => {
        let msg = e.to_string();
        if msg.contains("non-zero error code") {
            // child diagnostics are on inherited stderr just above; surface command context
            tracing::error!("child failed: {msg}");
        }
        return Err(e);
    }
}

Prevention

When it happens

Trigger: Any spawned helper binary exiting non-zero: linera-spawn during fungible benchmark setup, linera generate-initial-validator-config, storage initialization (initialize_storage), validator config generation, or linera project new/publish failing validation.

Common situations: Port already in use by a previous test run; missing tokio/rocksdb/dynamodb dependency or bad --storage URL; project publish with an invalid linera.toml; the spawned linera binary built from stale code that panicked; PATH resolving to an old binary.

Related errors


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