The wrapper that only looked for two

A devcontainer rebuild failure on Apple Silicon traced back to a browser launcher that matched x86 and legacy Chromium cache paths but missed ARM64.

A devcontainer rebuild on an Apple Silicon workstation failed immediately after installing the first model context protocol server. The install sequence halted inside the post-create script when the Playwright browser automation wrapper exited with an error during its startup health check. The failure had nothing to do with broken dependencies or missing system libraries: the script was searching for a cached Chromium binary, but its search filter only recognized x86 directory structures and was completely blind to the architecture-specific folder created on ARM64 hardware.

# .devcontainer/playwright-mcp-launch.sh
CHROME_BIN=$(
  find "$CACHE_DIR" -maxdepth 3 -type f \
    \( -path '*/chromium-*/chrome-linux/chrome' \
    -o -path '*/chromium-*/chrome-linux64/chrome' \
    -o -path '*/chromium-*/chrome-linux-arm64/chrome' \) \
    -perm -u+x | sort -V | tail -1
)

Bypassing the channel mismatch#

The search wrapper exists because running headless browsers from an agent toolchain is surprisingly fragile. When the project introduced custom shell wrappers for local tools, it discovered that the browser MCP server bundles its own prerelease version of the browser automation core, which expects a different revision of Chromium than the project test suite. Asking the server to launch its default browser resolves to a separate branded distribution channel that is not preinstalled in the container, and invoking its automated browser installer risked overwriting the cached binaries used by end-to-end tests. To insulate the container, a wrapper script intercepts execution, locates whichever valid Chromium binary already exists in the local cache, and passes that exact executable path to the server.

The script was searching for a cached binary, but its filter was completely blind to ARM64 hardware.

That path resolution worked reliably on Intel machines and CI runners, where Chrome for Testing extracts into chrome-linux64, or older builds that simply used chrome-linux. On Apple Silicon hosts, however, Docker runs a Linux ARM64 container, and the browser automation library unpacks the ARM64 build into chrome-linux-arm64. Because the launcher pattern only evaluated the first two directory names, the file lookup returned nothing. With no executable discovered, the script exited with a failure code, triggering the shell strict error-handling settings and aborting the devcontainer build right after earlier servers finished installing.

Verifying against the bundled registry#

Confirming the naming convention meant looking directly into the automation library’s bundled registry code, where internal architecture mapping pairs Linux ARM64 directly with the three-part directory name. Adding that third path alternative to the search query restored binary detection on ARM64 hosts without touching the existing x86 or legacy fallbacks. Verifying the fix against an unpacked directory layout confirmed that the pattern matched the ARM64 binary and passed the startup check.

Recording the three directory variants in the developer environment gotchas ensures the wrapper will not be accidentally reverted during future cleanup. As long as the container relies on a shared browser cache across multiple tools and architectures, launcher scripts have to accommodate every platform variation the underlying engine chooses to emit.