Fixing Zeabur Deployment Errors: exec format error, No such file, and symbol not found Explained

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.

CChia1104
Notes3 minutes read

Problem Symptoms

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.

Root Causes

exec ./server: no such file or directory

Why 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 Mismatch

This 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?

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.

Correct Solution: Align Architecture and libc

The key principle is simple:
The build target must match the runner’s OS and libc configuration for stable execution.

Zeabur Environment

  • Build produces amd64 + musl binary.
  • Runner also uses Alpine (musl).

With both architecture and libc aligned, the service can start normally in Zeabur.

services/auth/package.json
{
  "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"
  }
}
Dockerfile
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"]

Written by: Chia1104 CC BY-NC-SA 4.0

Chia1104
©
Chia1104