Skip to content

Commit 69b2c89

Browse files
leex279Archonclaude
authored
fix(docker): resolve Claude binary to glibc variant on Debian image (#1521)
* fix(docker): resolve Claude binary to glibc variant on Debian image Bun's hoisted linker installs both glibc and musl optional-dep packages for the detected CPU arch. The SDK's resolver picks musl first, which fails to execute on the Debian (glibc) base image — the musl dynamic loader is absent, causing every Claude call to fail. Remove the stale ENV CLAUDE_BIN_PATH pointing to the SDK 0.1.x cli.js path (no longer present in SDK 0.2.x), and add runtime arch detection in docker-entrypoint.sh. The entrypoint maps uname -m output to the correct glibc package suffix (x86_64→linux-x64, aarch64→linux-arm64) and exports CLAUDE_BIN_PATH before exec-ing the server. Users can still override via CLAUDE_BIN_PATH in their .env or docker run -e. Closes #1519 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(docker): warn on unsupported CPU arch in CLAUDE_BIN_PATH detection Add a *) fallback branch so operators on unsupported architectures (riscv64, ppc64le, etc.) get an explicit warning at startup rather than a silent no-op followed by a cryptic SDK error later. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(docker): verify glibc Claude binary exists before pinning CLAUDE_BIN_PATH Add a file-existence check after the uname -m arch detection so a missing or renamed binary in a future SDK version emits a clear WARN at startup rather than letting the container start cleanly and failing silently on first Claude invocation. Follows the project's Fail Fast principle: surface the problem as early as possible with an actionable message. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(docker): fail fast on unsupported arch or missing Claude binary The arch-detection block warned and continued in two failure modes — unsupported CPU and missing pinned binary — which left CLAUDE_BIN_PATH unset and silently fell through to the SDK's musl-first resolver, the exact bug this fix targets. Exit non-zero in both cases so startup surfaces a clear error instead of a delayed runtime failure. Also switch the existence check from -f to -x (the next thing we do with the path is execute it) and unset the helper var so it doesn't leak into the child process environment. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Archon <archon@archon.dev> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 4631b8e commit 69b2c89

2 files changed

Lines changed: 25 additions & 7 deletions

File tree

Dockerfile

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends nodejs npm \
108108
# Point agent-browser to system Chromium (avoids ~400MB Chrome for Testing download)
109109
ENV AGENT_BROWSER_EXECUTABLE_PATH=/usr/bin/chromium
110110

111-
# Pre-configure the Claude Code SDK cli.js path for any consumer that runs
112-
# a compiled Archon binary inside (or extending) this image. In source mode
113-
# (the default `bun run start` ENTRYPOINT), BUNDLED_IS_BINARY is false and
114-
# this variable is ignored — the SDK resolves cli.js via node_modules. Kept
115-
# here so extenders don't need to rediscover the path.
116-
# Path matches the hoisted layout produced by `bun install --linker=hoisted`.
117-
ENV CLAUDE_BIN_PATH=/app/node_modules/@anthropic-ai/claude-agent-sdk/cli.js
111+
# CLAUDE_BIN_PATH is set at container startup (docker-entrypoint.sh).
112+
# The entrypoint pins the glibc variant to bypass the SDK's musl-first resolver.
118113

119114
# Create non-root user for running Claude Code
120115
# Claude Code refuses to run with --dangerously-skip-permissions as root for security

docker-entrypoint.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,29 @@ if [ -n "$GH_TOKEN" ]; then
3737
'!f() { echo "username=x-access-token"; echo "password=${GH_TOKEN}"; }; f'
3838
fi
3939

40+
# Pin the glibc Claude Code binary to bypass the SDK's musl-first resolver.
41+
# Bun's hoisted linker installs both glibc and musl optional-dep variants for
42+
# the current CPU arch; the SDK picks musl first, which fails to execute on
43+
# this Debian (glibc) image. Only sets CLAUDE_BIN_PATH if the user has not
44+
# already provided one via docker run -e or docker-compose env_file.
45+
if [ -z "${CLAUDE_BIN_PATH:-}" ]; then
46+
case "$(uname -m)" in
47+
x86_64) _CLAUDE_BIN_CANDIDATE="/app/node_modules/@anthropic-ai/claude-agent-sdk-linux-x64/claude" ;;
48+
aarch64) _CLAUDE_BIN_CANDIDATE="/app/node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64/claude" ;;
49+
*)
50+
echo "ERROR: Unsupported CPU architecture $(uname -m). Set CLAUDE_BIN_PATH manually to a glibc Claude binary." >&2
51+
exit 1
52+
;;
53+
esac
54+
if [ -x "$_CLAUDE_BIN_CANDIDATE" ]; then
55+
export CLAUDE_BIN_PATH="$_CLAUDE_BIN_CANDIDATE"
56+
else
57+
echo "ERROR: Pinned Claude binary missing or non-executable at ${_CLAUDE_BIN_CANDIDATE}. The SDK package layout may have changed; set CLAUDE_BIN_PATH manually." >&2
58+
exit 1
59+
fi
60+
unset _CLAUDE_BIN_CANDIDATE
61+
fi
62+
4063
# Run setup-auth (exits after configuring Codex credentials), then exec the server
4164
# exec ensures bun is PID 1 and receives SIGTERM for graceful shutdown
4265
$RUNNER bun run setup-auth

0 commit comments

Comments
 (0)