RAPID INCIDENT TRIAGE & ACTION PLAN•Performance
01. Error Signature
M1 Mac Docker Buildx Hang Debugger
02. Root Cause Vector

docker-compose up hangs indefinitely at the 'Building' stage on M1 Macs due to a Rosetta/buildx platform emulation deadlock.

03. Rapid Prescription

Sort lock acquisition order deterministically, or configure explicit session timeouts.

Zero-Trust Client IDE/ Performance

M1 Mac Docker Buildx Hang Debugger

docker-compose up hangs indefinitely at the 'Building' stage on M1 Macs due to a Rosetta/buildx platform emulation deadlock.

SYSTEM STATUS
CREDITS: 0 / 3
source.yaml(25L)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Dockerfile for legacy-api (M1 Mac compatibility layer)
# TODO: This is a mess, but we need to support both x86_64 and arm64 for the PCI zone.
# VULNERABILITY: Buildx hang on M1 due to mixed platform emulation and Rosetta conflicts in multi-stage builds.
FROM --platform=linux/amd64 ubuntu:20.04 AS base
# Old base for PCI compliance, can't upgrade due to legacy dependencies
ENV AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
ENV AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
RUN apt-get update && apt-get install -y python3.8 \
    && rm -rf /var/lib/apt/lists/*
# Workaround for M1: trying to force x86 but buildx may hang on Rosetta
FROM --platform=linux/arm64/v8 alpine:3.14 AS builder
# Stripe key for payment processing (dev only, rotate in prod)
ENV STRIPE_API_KEY=sk_test_4eC39HqLyjWDarjtT1zdp7dc
RUN apk add --no-cache go=1.16 \
    && go build -o /app ./cmd/legacy-api
# Final stage with mixed platform inheritance
FROM base
# SSH private key for internal git access (temporary)
COPY --from=builder /app /usr/local/bin/
ADD id_rsa /root/.ssh/id_rsa
RUN echo "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEArX8tJfX7vJzK8LmKjQkXJzNvQ7tHqGpLmNoRstNqYwZvW3H\n... (truncated for brevity) ...\n-----END RSA PRIVATE KEY-----" > /root/.ssh/id_rsa \
    && chmod 600 /root/.ssh/id_rsa
# Database URI with credentials
ENV DATABASE_URI=postgresql://user:SecurePass123!@pci-secure-zone.internal:5432/legacy_db
CMD ["/usr/local/bin/app"]
AI Audit Console
> Waiting for pre-flight audit...
HybridRedactor Engine: Active
TECHNICAL WHITEPAPER & ARCHITECTURE SPEC•Updated 2026

How to Fix docker-compose Hanging at 'Building' with docker buildx on M1 Mac (Rosetta Deadlock)

Threat/Impact Level: HIGH | Downtime Risk: HIGH | Time to Fix: 10–20 mins


TL;DR

  • What broke: docker-compose up --build silently hangs at => [internal] load build definition because the docker-container buildx driver is trying to emulate linux/amd64 via Rosetta, and the builder context or QEMU layer deadlocks with no timeout and no error output.
  • How to fix it: Pin platform: linux/arm64 in your docker-compose.yml, ensure your active buildx builder uses the docker driver (not docker-container), and disable Rosetta emulation for the build context.
  • Sandbox: Use our Client-Side Sandbox above to auto-refactor your docker-compose.yml and Dockerfile — no data leaves your browser.

▼ 🔍 Root Cause Breakdown & Kernel Diagnostics [Click to Expand Deep Dive]

The Incident (What Does the Error Mean?)

You run docker-compose up and the terminal freezes here, indefinitely:

[+] Building
 => [internal] load build definition from Dockerfile          0.0s
 => => transferring dockerfile: 2.34kB                        0.0s
 => [internal] load .dockerignore                             0.0s
 => [internal] load metadata for docker.io/library/node:18    

No progress. No error. No timeout. CPU sits at 0%. The process is alive but nothing is happening. Ctrl+C sometimes doesn't even kill it cleanly.

Immediate consequence: Your entire local dev loop is broken. CI pipelines that mirror this local setup will also hang if they run on ARM runners without explicit platform flags. Engineers waste 30–90 minutes before realizing this isn't a network issue.


▼ 🔍 Detailed Impact & Blast Radius Analysis [Click to Expand Deep Dive]

The Attack Vector / Blast Radius

This is a silent deadlock, which makes it more dangerous than a loud crash. The failure chain:

  1. Docker Desktop on M1 defaults to the docker-container buildx driver when you install or reset buildx. This driver spins up a BuildKit container.
  2. If your docker-compose.yml has no platform: directive, BuildKit defaults to linux/amd64 (matching the image's published architecture).
  3. BuildKit attempts to pull or use a linux/amd64 base image, routing through Rosetta 2 binary translation layer.
  4. A known race condition in the BuildKit gRPC connection + Rosetta's dynamic translation of certain syscalls causes the build context transfer to stall. The client waits for an ACK that never comes.
  5. No timeout is set by default. Docker will wait forever.

Blast radius beyond local dev:

  • Any docker build in CI using a self-hosted ARM runner (GitHub Actions macos-14, AWS Graviton) without --platform will reproduce this.
  • Teams using docker buildx bake with multi-platform manifests will see intermittent hangs depending on layer cache state.
  • If your compose file is used in production-like staging via Portainer or Swarm on ARM nodes, the same hang can freeze a deployment pipeline.

How to Fix It (The Solution)

Basic Fix — Pin the Platform and Reset the Builder

Step 1: Nuke the broken builder and create a clean one using the docker driver.

# List builders — identify the hanging one
docker buildx ls

# Remove the broken builder
docker buildx rm multiarch-builder

# Create a new builder using the simple 'docker' driver (no BuildKit container)
docker buildx create --name local-arm-builder --driver docker-container --platform linux/arm64 --use

# OR — for pure local builds, just switch back to the default docker driver
docker buildx use default

Step 2: Add platform to your docker-compose.yml.

version: '3.9'
services:
  api:
-   image: node:18
+   image: node:18
+   platform: linux/arm64
    build:
      context: .
      dockerfile: Dockerfile
+     args:
+       BUILDKIT_INLINE_CACHE: "1"
    ports:
      - "3000:3000"

Step 3: Pin the platform in the Dockerfile itself.

- FROM node:18
+ FROM --platform=linux/arm64 node:18

  WORKDIR /app
  COPY package*.json ./
  RUN npm ci
  COPY . .
  CMD ["node", "server.js"]

Enterprise Best Practice — Enforce Platform Parity Across All Environments

For teams with mixed ARM/x86 developers and CI runners, hardcoding linux/arm64 locally and linux/amd64 in CI is a maintenance nightmare. The correct pattern:

Use a TARGETPLATFORM build arg and a .env file to control platform at runtime.

# docker-compose.yml
version: '3.9'
services:
  api:
+   platform: ${DOCKER_DEFAULT_PLATFORM:-linux/arm64}
    build:
      context: .
      dockerfile: Dockerfile
+     args:
+       - TARGETPLATFORM=${DOCKER_DEFAULT_PLATFORM:-linux/arm64}
    ports:
      - "3000:3000"
# Dockerfile
- FROM node:18
+ ARG TARGETPLATFORM
+ ARG BUILDPLATFORM
+ FROM --platform=${TARGETPLATFORM:-linux/arm64} node:18

+ RUN echo "Building on $BUILDPLATFORM for $TARGETPLATFORM"
  WORKDIR /app
  COPY package*.json ./
  RUN npm ci
  COPY . .
  CMD ["node", "server.js"]
# .env (committed to repo, platform-agnostic default)
+ DOCKER_DEFAULT_PLATFORM=linux/arm64
# CI pipeline (GitHub Actions) — override for x86 runners
  - name: Build
+   env:
+     DOCKER_DEFAULT_PLATFORM: linux/amd64
    run: docker-compose up --build -d

This lets every developer and CI runner declare their own platform without modifying shared files.


💡 Tired of pasting proprietary infrastructure configs into public LLMs? Generic AI interfaces log your company's ARNs, connection strings, and private keys. StackEngine enforces client-side zero-trust boundaries—the sandbox above executes 100% locally in your browser. Drop your broken manifest above to redact secrets locally and synthesize deterministic patch drafts with your own API key.

(For CI/CD pipeline automation, install via npm i -g stackengine).


▼ 🔍 Continuous Pipeline Governance & CI/CD Guardrails [Click to Expand Deep Dive]

Prevention in CI/CD

1. Hadolint — Lint Dockerfiles in CI

# .github/workflows/lint.yml
- name: Lint Dockerfile
  uses: hadolint/hadolint-action@v3.1.0
  with:
    dockerfile: Dockerfile
    failure-threshold: warning

Hadolint rule DL3029 flags FROM statements missing --platform, which is exactly the root cause here.

2. OPA/Conftest — Policy-Gate docker-compose Files

# policy/compose_platform.rego
package compose

deny[msg] {
  service := input.services[name]
  not service.platform
  msg := sprintf("Service '%v' is missing a 'platform' directive. Builds will be non-deterministic on ARM hosts.", [name])
}
conftest test docker-compose.yml --policy policy/

3. Pre-commit Hook — Block Commits Without Platform Pin

# .pre-commit-config.yaml
- repo: local
  hooks:
    - id: check-compose-platform
      name: Verify docker-compose platform directive
      language: pygrep
      entry: 'platform:'
      files: docker-compose\.yml
      args: [--negate]
      pass_filenames: true

4. Docker Desktop Setting (Nuclear Option)

If your entire team is on M1/M2, disable Rosetta emulation globally in Docker Desktop:

Docker Desktop → Settings → General → Uncheck "Use Rosetta for x86/amd64 emulation on Apple Silicon"

This forces all linux/amd64 builds to use QEMU instead of Rosetta. Slower, but no deadlocks.

5. Set a Build Timeout as a Safety Net

# In your Makefile or CI script — never let a build hang forever
timeout 300 docker-compose up --build || (echo "BUILD TIMED OUT" && exit 1)

Official Grounding & Normative Specifications

The technical diagnostics, error recovery protocols, and prevention patterns in this specification are grounded in official vendor documentation and standards:

Diagnostic & Architectural FAQ

Q1.Why does docker buildx hang with no error message on M1 Mac?
The root cause is a silent, low-level race condition in the gRPC handshake between the Docker CLI and the BuildKit daemon when Rosetta 2 emulates `linux/amd64`. This deadlock occurs because the `docker-container` driver runs BuildKit in a container, and the asynchronous communication has no default timeout, leaving you with a hanging build and zero diagnostic output. This isn't a simple bug—it's a systemic failure in cross-platform orchestration that erodes developer trust and halts productivity.
Q2.Should I use 'linux/arm64' or 'linux/amd64' in my docker-compose.yml on an M1 Mac?
Manually switching to `linux/arm64` is a brittle workaround that introduces severe risk. Forgetting to update a single `FROM` instruction or downstream dependency can silently revert to `linux/amd64`, re-triggering the hang or, worse, deploying misaligned images that fail in production. This manual patching is error-prone and creates security gaps through inconsistent platform enforcement. Instead of guessing, drop your broken `docker-compose.yml` into the StackEngine Local Sandbox above to automatically compile a zero-trust fix that locks down your platform targets and eliminates the blast radius.
Q3.Will disabling Rosetta in Docker Desktop fix the buildx hang permanently?
Disabling Rosetta merely swaps a deadlock for crippling 3–10x slower QEMU emulation, which is unsustainable at scale. In large mono-repos or enterprise CI/CD pipelines, manually managing platform flags across hundreds of services becomes a compliance nightmare, risking audit failures and deployment drift. For automated, on-prem remediation that enforces platform policies across every commit and environment, upgrade to the StackEngine CI/CD Automator (Team Edition). It integrates directly into your CI/CD to eliminate manual toil and ensure consistent, secure builds without performance penalties.