cross-rs/cross · error · eyre::ErrReport

container already exited due to signal

Error message

container already exited due to signal

What it means

The `bail_container_exited!` macro aborts a pending container command when the managed child container has already terminated (e.g. killed by a signal during cleanup). It only bails if `ChildContainer::exists_static()` reports the container no longer exists, preventing commands against a dead container/volume.

Solutions

  1. Re-run the cross command; the stale container state is cleaned up on the next invocation.
  2. Inspect `docker ps -a` / `docker volume ls` for orphaned cross containers/volumes and remove them.
  3. Avoid sending signals mid-build, or handle graceful shutdown so cleanup completes before exit.
Defensive patterns

Strategy: try-catch

Validate before calling

if !ChildContainer::exists_static() {
    // container gone: skip the command and re-run from a clean state
}

Try / catch

match run_in_container(...) {
    Err(e) if e.to_string().contains("container already exited") => {
    eprintln!("container exited early; cleaning up and retrying");
    cleanup();
}
Err(e) => return Err(e),
Ok(v) => v,
}

Prevention

When it happens

Trigger: Executing a docker subcommand against a cross-managed container after the container process received a signal (SIGINT/SIGTERM) or exited during volume cleanup — detected via the `exists_static` check failing.

Common situations: Pressing Ctrl-C while a cross build runs in Docker, CI timeout signals killing the container, or the container crashing mid-operation and subsequent commands racing against its cleanup.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of cross-rs/cross@8c1a8aa4b6 (2026-09-13). Data as JSON: /api/errors/969d0287d31bfa63. Report an issue: GitHub.

Appendix: source

Thrown at src/docker/remote.rs:29

use super::engine::Engine;
use super::shared::*;
use crate::TargetTriple;
use crate::config::bool_from_envvar;
use crate::errors::Result;
use crate::extensions::CommandExt;
use crate::file::{self, PathExt, ToUtf8};
use crate::rustc::{self, QualifiedToolchain, VersionMetaExt};
use crate::shell::MessageInfo;
use crate::temp;

// prevent further commands from running if we handled
// a signal earlier, and the volume is exited.
// this isn't required, but avoids unnecessary
// commands while the container is cleaning up.
macro_rules! bail_container_exited {
    () => {{
        if !ChildContainer::exists_static() {
            eyre::bail!("container already exited due to signal");
        }
    }};
}

#[track_caller]
fn subcommand_or_exit(engine: &Engine, cmd: &str) -> Result<Command> {
    bail_container_exited!();
    Ok(engine.subcommand(cmd))
}

pub fn posix_parent(path: &str) -> Option<&str> {
    Path::new(path).parent()?.to_str()
}

impl ContainerDataVolume<'_, '_, '_> {
    // NOTE: `reldir` should be a relative POSIX path to the root directory
    // on windows, this should be something like `mnt/c`. that is, all paths
    // inside the container should not have the mount prefix.

View on GitHub (pinned to 8c1a8aa4b6)