UndefinedVar: Usage of undefined variable '$APP_VERSION' is a build-check warning, but unlike most of its siblings it points at a real bug: the variable expands to an empty string and the build carries on. The usual cause is an ARG declared before FROM and not declared again after it. Add ARG APP_VERSION (no value) below the FROM line.

An ARG above FROM is visible to the FROM line only. Inside the stage you must name it again; it then keeps the default from the top.

The error

 1 warning found (use docker --debug to expand):
 - UndefinedVar: Usage of undefined variable '$APP_VERSION' (line 3)

The build exited with code 0, and the step that printed the variable showed the damage: #5 0.201 version=, with nothing after the equals sign. The terminal colour codes in the captured warning lines are left out. An image built this way carries an empty APP_VERSION_LABEL, which is easy to miss until something reads it.

Why it happens

The Dockerfile was:

ARG APP_VERSION=1.2.3
FROM alpine
ENV APP_VERSION_LABEL=$APP_VERSION
RUN echo "version=$APP_VERSION_LABEL"

Each FROM starts a new build stage with its own set of build arguments. An ARG before the first FROM is outside every stage, so on line 3 $APP_VERSION has no value and the ENV becomes empty. Docker does not stop for that; it warns, because an empty variable is a valid value.

The check works on Dockerfile instructions. In an earlier attempt the variable was used only inside a RUN command, RUN echo "version=$APP_VERSION" > /version.txt, followed by RUN cat /version.txt; the cat step printed version= as well, but no warning appeared. The build log showed the first step with $APP_VERSION unexpanded, so the shell inside the container did the expansion. A missing warning does not prove the variable is set.

The fix

ARG APP_VERSION=1.2.3
FROM alpine
ARG APP_VERSION
ENV APP_VERSION_LABEL=$APP_VERSION
RUN echo "version=$APP_VERSION_LABEL"

Built again, the log had no warning and the step printed version=1.2.3. The bare ARG APP_VERSION inside the stage inherits the default from the top of the file, as the printed 1.2.3 shows.

How it was reproduced

The four-line Dockerfile above on alpine, built with docker build --progress=plain -t fix8-bld-q4 fix8-bld-q4 on Docker Desktop engine 29.9.2; the fixed five-line file built into fix8-bld-q4fix. Tags and folders are this test's own.

Frequently asked

Why is my Docker ARG empty after FROM?
An ARG declared before FROM is only visible to the FROM line. Declare ARG NAME again inside the stage; it keeps the default from the top.
Does UndefinedVar fail the Docker build?
No. The build exits with code 0, but the variable expands to an empty string, so the image may be wrong. Treat this warning as a bug.
Why is there no UndefinedVar warning for a variable used in RUN?
In the test, a RUN command using the same unset variable printed an empty value without the warning. The shell in the container expanded it, so check the printed value, not only the warnings.

More decoded errors in the Fixes category, including the LegacyKeyValueFormat warning.