Azure / Azure/azure-dev

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

Open
#9,069 0 comments 1 reaction 2 assignees Claimed by @bterlson View on GitHub
area/bicep area/installer bug
Dominant language
Go
Stars
569
Forks
364
Avg merge
2d 19h
Merged PRs (30d)
136

Description

### 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**:

```go
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 --version` → `0.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

- #2593 (closed) — earlier arm64/M1 dev-container manifestation of a bicep-under-qemu failure.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.