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.

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.

Appendix: 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)