mando-cli v0.4.0 — mando up fails on missing target/release/mando_bess (2026-06-25)
The next failure after the 2026-05-26 compose-runtime triage fixes (commit 2233959): once the context: and mocked-slug bugs were resolved, mando up on a fresh clone with the default profile now aborts inside docker compose build because the mando runconfig is build, but mando/Dockerfile is a thin runtime image that COPYs a pre-compiled target/release/mando_bess — and nothing in the up flow ever compiles it.
For Agents
This is a design gap, not a runtime bug: the default profile mando-mocked-algos maps mando → the build runconfig, and the build runconfig + mando/Dockerfile assume cargo build --release already ran (a CI-only invariant). On any fresh checkout the COPY layer has no binary and the whole stack build aborts. Workaround today: mando up --mando=pull (pulls the released registry image instead of building). Durable fix is a 2-part decision pending user sign-off (flip default to pull + add a preflight guard) — NOT yet implemented.
Status
Diagnosed, fix pending user decision. No code change committed. The v0.4.0 binary distributed via install.ps1 cannot run the default mando up on a clean checkout without the workaround.
Reporter
gabi (gabriel.vasile1), remote QA tester, on WSL, mando-cli v0.4.0, date 2026-06-25.
Running default mando up (profile mando-mocked-algos) on a fresh clone.
Symptom
mando up issues docker compose up -d --build and the build aborts at the mando image’s final COPY:
#14 [mando 6/6] COPY target/release/mando_bess /usr/local/bin/mando_bess
ERROR: failed to compute cache key: "/target/release/mando_bess": not found
Collateral: the bess-trader-dashboard build shows CANCELED (buildkit aborts sibling builds once one target fails), so the failure can read as a dashboard problem — it is not.
Root cause (verified by reading source)
The mando service’s runconfig under the default profile is build, which emits a real build: section pointing at mando/Dockerfile. But that Dockerfile is a thin runtime image that copies a pre-built binary — it does not compile from source — and no step in the up flow runs cargo build --release. So on a fresh checkout the binary the COPY expects does not exist.
1. mando/Dockerfile is a thin runtime image
FROM debian:13.1-slim AS runner# ... line 17:COPY target/release/mando_bess /usr/local/bin/mando_bess# ...CMD ["mando_bess"]
It copies a pre-compiled binary. There is no Rust build stage — building this image presupposes target/release/mando_bess already exists on the build context.
2. mando/bess-service.yaml:23-32 encodes the CI assumption
The context_includes list (the yaml-driven build-context filter from mando-cli-build-context-filter-2026-05-06) explicitly ships the pre-built binary into the build context. This only holds in CI, where cargo build --release precedes the image build.
3. The default profile maps mando → build (and so do the other builtins)
src/runtime/runprofile.rs:
Profile
mando runconfig
line
mando-mocked-algos (default)
build
runprofile.rs:225
mando-full
build
runprofile.rs:237
mando-fast-dev
build-dev
runprofile.rs:249
No builtin profile maps mando to pull or artifact. Every default path goes through a runconfig that wants the binary.
4. The build runconfig emits a real build: (nothing compiles mando_bess)
src/runtime/templates/runconfig/build.yml:10-12 renders a real build: block. The host-side compile flag --cargo that would produce the binary is gated to the artifact runconfig only (src/cli.rs:55) — it is not part of the build/up path. So the up flow:
picks build for mando (step 3),
renders a build: section (step 4),
never runs cargo build --release,
→ COPY of a non-existent binary → abort.
Net
Any tester on a fresh clone running the default mando up hits this. It works in CI only because CI pre-builds target/release/mando_bess before the compose build. This is the same class of “ships-as-the-default-but-never-exercised-against-a-fresh-checkout” gap called out in the 2026-05-26 process lesson.
Immediate workaround (no code change)
Unblock gabi now
mando up --mando=pull
The per-service override syntax --<service>=<runconfig> is documented at src/cli.rs:78. The pull runconfig (src/runtime/templates/runconfig/pull.yml) swaps the build: section for image: ${MANDO_IMAGE:-…} and adds a docker compose pull, so it fetches the released image instead of compiling.
and he is authenticated to that registry, so the pull succeeds and the stack comes up with the released mando image. (This ref is not hardcoded in mando-cli source — it comes from workspace config / env; see Risk under the durable fix.)
Durable fix (decision pending — NOT implemented)
Two parts; both require user sign-off before implementing.
Part 1 — flip the default profile’s mando runconfig build → pull
Change runprofile.rs:225 so mando-mocked-algos resolves mando to pull instead of build. A fresh clone would then pull the released image by default and never hit the COPY.
Open risk — confirm the clean-checkout default image ref
The pull runconfig’s image comes from ${MANDO_IMAGE:-…}. The registry ref is NOT hardcoded in mando-cli source — it is supplied by workspace config / env. Before flipping the default, confirm a clean checkout’s default MANDO_IMAGE points at the GitLab registry (e.g. the registry.gitlab.com/.../mando:<tag> above), not a local tag like mando:dev. If the default resolves to a local-only tag, the pull 404s for anyone who hasn’t built locally — trading one fresh-clone failure for another.
Part 2 — add a preflight guard in up
If the resolved mando runconfig is build (or build-dev) and target/release/mando_bess is missing, fail early with an actionable message (e.g. “mando_bess not built — run cargo build --release or use mando up --mando=pull”) instead of letting buildkit fail deep in the COPY layer with a cryptic cache-key error.
This guard is valuable independent of Part 1: anyone who deliberately selects the build runconfig (local source iteration) still benefits from the early, actionable failure.
Communicate workaround mando up --mando=pull to gabi
—
now
Related
mando-cli-v0.4.0-piped-output-invisible-failures-2026-06-25 — follow-up found while validating the --mando=pull workaround above. When up output is piped/redirected (the tester does 2>&1 | tee log), failures were INVISIBLE: docker compose writes progress+errors to /dev/tty (fix: --progress plain) and indicatif::MultiProgress::println is a non-TTY no-op (fix: eprintln! fallback on !stderr().is_terminal()). With both fixed, the workaround’s own wall became visible: a registry pull access denied (needs docker login, distinct from mando-cli’s GitLab-API auth).
mando-cli-v0.4.0-compose-bugs-triage-2026-05-26 — the previous failure on this exact path; its fixes landed in commit 2233959, and clearing them surfaced this binary-missing gap as the next blocker. Documents the load-bearing profiles: ["{run_tag}"] invariant and the default-mocked-profile-vs-fresh-checkout coverage hole.
mando-cli-v2 — current architecture (AppContext, CommandDelegate, runtime pipeline) that the profile/runconfig resolution lives in.
mando-cli-build-context-filter-2026-05-06 — the yaml-driven context_includes mechanism (bess-service.yaml) that ships the pre-built binary into the build context — the CI assumption made explicit.
mando-cli-wsl-linux-build — the install.sh / install.ps1 distribution channel that delivered the v0.4.0 binary gabi is running on WSL.
mando-cli-build-variants-shelved-2026-05-06 — shelved profile-driven build-variant design (dev vs release Dockerfile, pre_command) that, had it shipped, would have covered the “compile-then-image” path the default profile silently assumes.