claude-code image ships a broken native binary when npm's optionalDependencies fetch fails during build #353

Open
opened 2026-07-13 04:03:48 -04:00 by didericis-claude · 0 comments
Collaborator

Symptom

A bring-up on macos-container failed with two errors in sequence:

bot-bottle: warning: `claude mcp add supervise` failed (exit 1): Error: claude native binary not installed.
...
Error: failed to exec [claude --dangerously-skip-permissions --remote-control ...] Error Domain=NSPOSIXErrorDomain Code=8 "Exec format error"

Root cause

@anthropic-ai/claude-code@2.1.172 distributes its CLI as a native binary pulled in via a platform-specific optionalDependencies entry (e.g. @anthropic-ai/claude-code-linux-arm64), not the old JS-shim model. npm install -g in bot_bottle/contrib/claude/Dockerfile hit a transient failure fetching that optional package. npm treats optional-dependency install failures as non-fatal, so the overall npm install -g still exited 0, leaving a 500-byte stub bin/claude.exe that only prints "claude native binary not installed" at first invocation.

Because the npm-install RUN layer is Docker/BuildKit-cached, every subsequent container build reused the broken cached layer instead of retrying the fetch — the image looked “built successfully” indefinitely until forced to rebuild without cache. container run --rm --entrypoint claude bot-bottle-claude:latest --version reproduced it directly against the running image; claude.exe was 500 bytes instead of the real ~250MB binary.

Fix (see linked PR)

  1. Add a post-build smoke test: after building an agent image, run a provider-declared command (claude --version / codex's equivalent) inside a throwaway container of the freshly built image and fail loudly instead of shipping a broken image.
  2. Add a --no-cache flag (bot-bottle start --no-cache, also BOT_BOTTLE_NO_CACHE=1) to force a from-scratch rebuild when this happens again.

Out of scope / follow-up

bot_bottle/contrib/pi/Dockerfile installs @earendil-works/pi-coding-agent with --ignore-scripts, which would guarantee a broken postinstall if that package also ships a native binary this way. Not verified/fixed here — worth checking separately.

## Symptom A bring-up on `macos-container` failed with two errors in sequence: ``` bot-bottle: warning: `claude mcp add supervise` failed (exit 1): Error: claude native binary not installed. ... Error: failed to exec [claude --dangerously-skip-permissions --remote-control ...] Error Domain=NSPOSIXErrorDomain Code=8 "Exec format error" ``` ## Root cause `@anthropic-ai/claude-code@2.1.172` distributes its CLI as a native binary pulled in via a platform-specific `optionalDependencies` entry (e.g. `@anthropic-ai/claude-code-linux-arm64`), not the old JS-shim model. `npm install -g` in `bot_bottle/contrib/claude/Dockerfile` hit a transient failure fetching that optional package. npm treats optional-dependency install failures as non-fatal, so the overall `npm install -g` still exited 0, leaving a 500-byte stub `bin/claude.exe` that only prints "claude native binary not installed" at first invocation. Because the npm-install `RUN` layer is Docker/BuildKit-cached, every subsequent `container build` reused the broken cached layer instead of retrying the fetch — the image looked “built successfully” indefinitely until forced to rebuild without cache. `container run --rm --entrypoint claude bot-bottle-claude:latest --version` reproduced it directly against the running image; `claude.exe` was 500 bytes instead of the real ~250MB binary. ## Fix (see linked PR) 1. Add a post-build smoke test: after building an agent image, run a provider-declared command (`claude --version` / codex's equivalent) inside a throwaway container of the freshly built image and fail loudly instead of shipping a broken image. 2. Add a `--no-cache` flag (`bot-bottle start --no-cache`, also `BOT_BOTTLE_NO_CACHE=1`) to force a from-scratch rebuild when this happens again. ## Out of scope / follow-up `bot_bottle/contrib/pi/Dockerfile` installs `@earendil-works/pi-coding-agent` with `--ignore-scripts`, which would guarantee a broken postinstall if that package also ships a native binary this way. Not verified/fixed here — worth checking separately.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: didericis/bot-bottle#353