Deploying on Zeabur but seeing errors like exec format error, no such file or directory, or symbol not found? This guide explains the real root causes—CPU architecture and libc mismatches—and provides correct Dockerfile and build examples to ensure your app runs smoothly on Alpine and other environments.
Written by: Chia1104 CC BY-NC-SA 4.0
When deploying on Zeabur, the container startup may show errors such as:
exec ./server: no such file or directory – The file clearly exists, yet it says it cannot be found.exec ./server: exec format error – The executable file format or architecture is incompatible.symbol not found – The dynamic linking symbols cannot be resolved, often due to libc or loader incompatibility.exec ./server: no such file or directoryWhy does exec ./server: no such file or directory appear even though the file exists?
Many people assume this means the file is missing. In reality, the most common cause is libc/loader incompatibility.
This error is often mistaken for a failed COPY command or an incorrect file path. However, on Linux, even if a binary file physically exists, as long as it’s a dynamically linked ELF, and the interpreter defined inside the ELF (the loader, e.g. ld-linux...) is not present on the current system, the system will return No such file or directory.
One of the most common real-world scenarios is when the builder and runner use different libc implementations. For example, binaries built in an Alpine (musl) environment won’t run properly in a glibc-based environment (or vice versa), because the loader path or library dependencies don’t match—resulting in an error that looks like a missing file.
exec ./server: exec format error — Binary Architecture MismatchThis usually indicates that you’re running a binary built for a different CPU architecture. For example, trying to run an arm64 binary in an amd64 environment will produce an exec format error.
So your first check should be: what architecture was your binary built for (amd64 or arm64), and what architecture is your runner actually using?
symbol not found — Dynamic Linking Mismatch (Often libc Related)The symbol not found error is mostly related to dynamic linking. When a program starts, it must load certain shared libraries and resolve symbols. If the system’s available versions are incompatible, it will fail during startup.
This issue is especially common when switching between Alpine (musl) and Debian/Ubuntu (glibc) environments, since their loaders and libraries differ fundamentally.
The key principle is simple:
The build target must match the runner’s OS and libc configuration for stable execution.
With both architecture and libc aligned, the service can start normally in Zeabur.
{
"scripts": {
"build:amd64-musl": "bun build --compile --target bun-linux-x64-musl --minify-whitespace --minify-syntax --outfile .output/server src/server.ts",
"start": ".output/server"
}
}ARG NODE_VERSION=24
ARG TARGETARCH=amd64
FROM --platform=linux/${TARGETARCH} node:${NODE_VERSION}-alpine AS builder-base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
ENV TURBO_TELEMETRY_DISABLED=1
WORKDIR /app
RUN apk update && \
apk add --no-cache \
build-base \
gcc \
libc6-compat && \
npm install -g corepack@latest turbo bun && \
corepack enable pnpm
FROM builder-base AS pre-builder
COPY . .
RUN turbo prune --scope=auth-service --docker
FROM builder-base AS builder
COPY --from=pre-builder /app/out/json/ .
COPY --from=pre-builder /app/out/pnpm-lock.yaml ./pnpm-lock.yaml
COPY --from=pre-builder /app/out/full/ .
COPY turbo.json turbo.json
ARG TURBO_TEAM \
TURBO_TOKEN
ENV TURBO_TEAM=$TURBO_TEAM \
TURBO_TOKEN=$TURBO_TOKEN
RUN pnpm i
RUN pnpm -C services/auth build:amd64-musl
FROM --platform=linux/${TARGETARCH} alpine AS runner
RUN apk update && \
apk add --no-cache \
libstdc++
WORKDIR /app
COPY --from=builder /app/services/auth/.output/server server
ENV NODE_ENV=production \
PORT=8080
EXPOSE 8080
CMD ["./server"]