Skip to content

azd hard-fails instead of re-downloading when managed bicep is the wrong architecture / non-runnable #9069

Description

@bterlson

Output from azd version

azd version 1.27.1 (commit 257908961d465e98c1a6574eae9624a7954b21cf)

Describe the bug

On an arm64 machine, if azd's managed bicep copy at $AZD_CONFIG_DIR/bin/bicep (~/.azd/bin/bicep) is the wrong architecture (e.g. an x86-64 binary left behind by an older/x64 install), azd up / provision hard-fails instead of recovering:

ERROR: deployment failed: step "provision" failed: initializing layer provision: failed to compile bicepparam template: ensuring bicep is installed: checking bicep version: exit code: 255, stdout: , stderr: qemu-x86_64: Could not open '/lib64/ld-linux-x86-64.so.2': No such file or directory

The native (arm64) azd binary runs fine — only the managed bicep is the wrong arch, so the OS tries to run it under qemu-x86_64 binfmt emulation, which fails because the x64 glibc loader isn't installed.

Root cause

In cli/azd/pkg/tools/bicep/bicep.go, ensureInstalled only downloads bicep when the file is missing:

if errors.Is(err, os.ErrNotExist) {
    ... downloadBicep(...)
}
cli.path = bicepPath

ver, err := cli.version(ctx)   // runs `bicep --version`
if err != nil {
    return fmt.Errorf("checking bicep version: %w", err)   // <-- hard fail
}

When a (broken) binary already exists, azd skips the download, runs bicep --version, that fails to execute, and azd returns the error rather than replacing the bad binary. There is no self-heal path for a non-runnable / wrong-arch / corrupted managed bicep.

Note azd intentionally does not fall back to a bicep on PATH (no exec.LookPath) — it manages its own version-pinned copy (Version = 0.44.1), overridable only via AZD_BICEP_TOOL_PATH. That's by design for reproducibility, but it means a corrupt managed copy is a dead end without manual intervention.

Expected behavior

When the existing managed bicep fails its version check (can't execute — wrong arch, corrupted, or partial download), azd should re-download it once and retry, then fail only if the fresh copy still can't run. Freshly-downloaded binaries should not loop.

To reproduce

  1. On an arm64 Linux/WSL host, place an x86-64 bicep at ~/.azd/bin/bicep (or have one left from a prior x64 azd install).
  2. Run azd up (or azd provision).
  3. Observe the qemu-x86_64: Could not open '/lib64/ld-linux-x86-64.so.2' failure.

Environment

  • arm64 WSL (Ubuntu, glibc). uname -m = aarch64.
  • azd is native arm64; the stale ~/.azd/bin/bicep was x86-64 (file reports ELF 64-bit LSB pie executable, x86-64).
  • Deleting ~/.azd/bin/bicep makes azd re-download the correct bicep-linux-arm64 and resolves it (verified: bicep --version0.44.1).

Workarounds

  • rm ~/.azd/bin/bicep and re-run (azd re-downloads the correct arch), or
  • export AZD_BICEP_TOOL_PATH="$(command -v bicep)" to point azd at a working bicep on PATH (must be ≥ the pinned version).

Proposed fix

In ensureInstalled, track whether we just downloaded; if the version check fails on a pre-existing binary, re-download once (via the existing downloadBicep atomic temp-file+rename path) and re-check. Add a unit test that seeds a non-runnable file and asserts a single re-download + success.

Related

Metadata

Metadata

Labels

area/bicepBicep-specific provisioningarea/installerInstall scripts, MSI, self-updatebugSomething isn't working

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions