dockerseverity: can-fix
ARG not set

Docker: ARG variable not set during build — empty string substitution

ARG not set — empty substitution in Dockerfile

99% fixable~5 mindifficulty: beginner

Verified against Docker docs: Dockerfile reference — ARG, Moby source: builder/dockerfile/dispatchers.go, Docker BuildKit documentation · Updated June 2026

> quick_fix

Your Dockerfile declares ARG but you didn't pass --build-arg at build time, so it evaluates to an empty string. Either pass it with docker build --build-arg VAR=value or set a default in the Dockerfile with ARG VAR=default_value.

# Dockerfile declares: ARG APP_VERSION
# But you ran: docker build .
# Fix 1 — pass at build time:
docker build --build-arg APP_VERSION=1.2.3 .

# Fix 2 — set default in Dockerfile:
# ARG APP_VERSION=latest

What causes this error

Docker's ARG instruction declares a build-time variable. Unlike ENV, ARG values are not persisted into the running container — they exist only during docker build. If you declare ARG APP_VERSION but don't pass --build-arg APP_VERSION=value when building, the variable resolves to an empty string. This is silent — Docker doesn't warn you. The empty string then propagates into RUN, COPY, and LABEL instructions that reference $APP_VERSION, causing subtle failures: wrong image tags, missing files, broken labels.

> advertisementAdSense placeholder

How to fix it

  1. 01

    step 1

    Check which ARGs your Dockerfile declares

    Open the Dockerfile and search for ARG lines. Each one is a variable that must be supplied at build time (unless it has a default value after the = sign).

  2. 02

    step 2

    Pass missing values with --build-arg

    For each ARG without a default, pass it explicitly: docker build --build-arg APP_VERSION=1.2.3 --build-arg NODE_ENV=production .

    docker build \
      --build-arg APP_VERSION=1.2.3 \
      --build-arg NODE_ENV=production \
      -t myapp:1.2.3 .
  3. 03

    step 3

    Add defaults for optional ARGs

    If an ARG should have a sensible fallback, declare it with a default value: ARG NODE_ENV=production. This way, omitting --build-arg uses the default instead of empty string.

  4. 04

    step 4

    Verify ARG values in the build output

    Add a RUN echo "APP_VERSION=$APP_VERSION" line temporarily to confirm the variable resolves correctly during build. Remove it after verification.

How to verify the fix

  • docker build completes without empty-string substitution warnings.
  • RUN echo "$VAR" prints the expected value in build output.
  • The resulting image behaves correctly with the substituted values.

Why ARG not set happens at the runtime level

Docker's Dockerfile parser processes ARG instructions by registering the variable name in the build context's argument map. When docker build runs, it merges --build-arg flags into this map. If a declared ARG has no matching --build-arg and no default value (the part after = in ARG VAR=default), the lookup returns an empty string. The substitution happens at the shell expansion level inside RUN instructions — the shell sees an empty variable, not an error. This is by design: Docker treats missing ARGs as empty strings rather than failing the build, which makes the failure mode silent and the bugs subtle.

Common debug mistakes for ARG not set

  • Declaring ARG after FROM and expecting it to be available in earlier stages — ARGs are scoped to the build stage they're declared in. A multi-stage build needs ARG redeclared in each stage that uses it.
  • Using ARG for runtime configuration and wondering why the container can't see the value — ARG disappears after build. Use ENV for runtime values, or do ENV VAR=$ARG_VAR to promote a build-arg to runtime.
  • Passing secrets via --build-arg thinking they're ephemeral — ARG values are baked into image layer metadata and visible via docker history. Use --secret or --ssh for sensitive data.
  • Expecting Docker Compose build.args to override Dockerfile defaults — Compose args do override defaults, but only if the Compose file actually lists the arg. A missing entry in compose.yml means the Dockerfile default wins silently.
  • Not quoting ARG references in RUN instructions — RUN curl $URL fails if URL contains spaces or special characters. Use RUN curl "$URL" for safety.

When ARG not set signals a deeper problem

Persistent ARG issues in a Docker workflow usually mean build configuration is scattered across too many places: Dockerfile defaults, docker-compose.yml overrides, CI pipeline variables, and Makefile targets. When a variable is declared in four places, the precedence rules become a debugging puzzle — especially in multi-stage builds where ARG scoping resets at each FROM. The architectural fix is to centralize build arguments in a single .env or build-args file, reference it from one place (Compose or CI), and eliminate Dockerfile defaults for anything environment-specific. This turns the implicit empty-string failure into an explicit missing-variable error.

Editor's take

The most painful ARG-not-set bug I've encountered was in a CI pipeline where the image tag was built from ARG GIT_SHA — which the CI system passed correctly on push events but not on scheduled builds. The nightly build silently tagged images as myapp: (empty string after the colon), which Docker accepted without complaint. The registry accumulated dozens of images with empty tags over two weeks before anyone noticed, and the deploy script's docker pull myapp:$SHA started pulling the wrong image on rollbacks because the empty-tag image had the highest layer cache hit rate.

Understanding ARG scoping in multi-stage builds — specifically that ARG declared before the first FROM is available only in FROM lines, and must be redeclared inside each stage — separates someone who copies Dockerfiles from someone who writes them. The mental model is: each FROM resets the build context. If you need a value in stage 2, you either redeclare the ARG or pass it through an ENV in the previous stage.

In the same debugging session you'll often find: COPY failing silently because a path variable was empty (copies nothing, no error), ENV references to ARG values that resolved to empty at build time (the ENV persists but contains nothing), and multi-stage COPY --from=builder paths that break because the builder stage used an empty ARG to determine the output directory.

By Bikram Nath · Curator · Updated June 2026

Frequently asked questions

What's the difference between ARG and ENV in a Dockerfile?

ARG is build-time only — it exists during docker build and disappears from the running container. ENV persists into the container's runtime environment. Use ARG for build-time configuration (version tags, build flags) and ENV for runtime configuration (database URLs, feature flags).

Can I use ARG values in the FROM instruction?

Yes, but only if the ARG is declared before the first FROM. ARG BASE_IMAGE=node:20 followed by FROM $BASE_IMAGE works. ARGs declared after FROM are scoped to that build stage.

Are ARG values visible in the image history?

Yes — docker history shows ARG values. Never pass secrets (API keys, passwords) via --build-arg. Use BuildKit's --secret flag instead for sensitive values.

disclosure:Errordex runs AdSense, has zero third-party affiliate or sponsored links, and occasionally links to the editor’s own paid digital products (clearly labelled). Every fix is cross-referenced against the official sources listed in the “sources” sidebar before it ships. If a fix here didn’t work for you, please email so we can update the page.