cross-rs/cross · warning

remote and docker-in-docker are unlikely to work together…

Error message

remote and docker-in-docker are unlikely to work together when using cross. remote cross uses data volumes, so docker-in-docker should not be required.

What it means

cross's remote mode manages data volumes itself, so running it inside docker-in-docker (nested Docker) is unnecessary and typically breaks volume sharing. When run() detects in_docker(), it warns that the combination is unlikely to work.

Solutions

  1. Run cross directly on the host (or outside the nested container) when using remote mode.
  2. Disable docker-in-docker by unsetting CROSS_CONTAINER_IN_CONTAINER / CROSS_DOCKER_IN_DOCKER.
  3. If nesting is unavoidable, mount the needed volumes explicitly through both Docker layers so the data volume is shared.

Example fix

# before (inside container)
export CROSS_CONTAINER_IN_CONTAINER=1
cross build --remote --target aarch64-unknown-linux-gnu

# after (on host)
unset CROSS_CONTAINER_IN_CONTAINER
cross build --remote --target aarch64-unknown-linux-gnu
Defensive patterns

Strategy: validation

Validate before calling

# Guard remote usage against nested docker
if [ -n "${CROSS_CONTAINER_IN_CONTAINER:-}" ] || [ -n "${CROSS_DOCKER_IN_DOCKER:-}" ]; then
  echo "remote mode unsupported under docker-in-docker"; exit 1
fi

Prevention

When it happens

Trigger: Calling run() for a remote build while in_docker() is true — i.e. the engine reports the cross container is itself running inside a Docker container (CROSS_CONTAINER_IN_CONTAINER set or detected).

Common situations: CI jobs that run cross inside a container with a Docker socket mounted and remote/cluster mode enabled; developers testing remote builds from a devcontainer.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at src/docker/remote.rs:758

    }
}

pub(crate) fn run(
    options: DockerOptions,
    paths: DockerPaths,
    args: &[String],
    subcommand: Option<crate::Subcommand>,
    msg_info: &mut MessageInfo,
) -> Result<Option<ExitStatus>> {
    let engine = &options.engine;
    let target = &options.target;
    let toolchain_dirs = paths.directories.toolchain_directories();
    let package_dirs = paths.directories.package_directories();

    let mount_prefix = MOUNT_PREFIX;

    if options.in_docker() {
        msg_info.warn("remote and docker-in-docker are unlikely to work together when using cross. remote cross uses data volumes, so docker-in-docker should not be required.")?;
    }

    // the logic is broken into the following steps
    // 1. get our unique identifiers and cleanup from a previous run.
    // 2. if not using persistent volumes, create a data volume
    // 3. start our container with the mounted data volume and all envvars
    // 4. copy data into the data volume
    //      with persistent data volumes, copy just copy crate data and
    //      if not present, the toolchain for the current target.
    //      otherwise, copy the entire toolchain, cargo, and crate data
    //      if `CROSS_REMOTE_COPY_CACHE`, copy over the target dir as well
    // 5. create symlinks for all mounted data
    //      ensure the paths are the same as local cross
    // 6. execute our cargo command inside the container
    // 7. copy data from target dir back to host
    // 8. stop container and delete data volume
    //
    // we use structs that wrap the resources to ensure they're dropped

View on GitHub (pinned to 8c1a8aa4b6)