An unset variable stays unset on the way into the container - #572
Merged
WaylandYang merged 2 commits intoSep 9, 2026
Merged
Conversation
Signed-off-by: Menglin Li <limenglin5911@gmail.com>
lml2468
force-pushed
the
fix/compose-blank-env-is-unset
branch
from
September 9, 2026 16:34
115f333 to
53b28d4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
docker compose --profile app up -d— the command the README promises — exits on the first step with a clean clone:Three variables are declared as
${VAR:-}. When the variable is not set on the host, that does not mean "don't pass it"; it passes an empty string.UTOPIA_MIGRATION_URL=""reaches sqlx, and sqlx cannot parse""as a URL.blank_is_unset(#344) fixed the Rust side, and its comment already names this shape:This is the other half: the empty string should never be sent in the first place. Writing the key with no value is the documented Compose form for "pass it through, and leave it unset if the host has not set it".
Why not just bump the default image
That was the first instinct, and it is worse.
0.1.0-rc5is the only published release tag, and it predates #344 — so bumping means pinning the README's headline command todev-ed397e7, a dev build, against the compose file's own instruction to pin a released version. Fixing the compose side means the already-published rc5 boots, and no new release is needed.Verified
Boots with the stock default unchanged (
0.1.0-rc5), on an otherwise untouched clone:Compose semantics checked directly, rather than assumed:
.envVAR: ${VAR:-}""VAR:from_env_filefrom_hostSo configuring any of the three still works exactly as before; only the "nobody set it" case changes.
The regression guard
release.yml's smoke test runsdocker rundirectly and never passes an emptyUTOPIA_MIGRATION_URL, which is precisely how #343 shipped green in rc5 and broke the first command a new user types. The smoke test now passes-e UTOPIA_MIGRATION_URL=so an empty string has to behave like unset.Confirmed the guard discriminates — it fails on the broken build and passes on the fixed one:
-e UTOPIA_MIGRATION_URL=0.1.0-rc5(pre-#344)exited:1—relative URL without a basedev-ed397e7(post-#344)running—Utopia 服务启动于 http://0.0.0.0:1516Deliberately left alone
db'sUTOPIA_APP_DB_PASSWORD: ${UTOPIA_APP_DB_PASSWORD:-}keeps its current form —init-app-role.shalready guards it with[ -z ], which is the checkconfig.rscites as the precedent forblank_is_unset.Records
No ADR status line to update: this changes no decision, it closes the deployment gap #343 named.
Testing
YAML-only change; no Rust or web sources touched.
docker compose configand a YAML parse both pass, and the boot above is the real check. The pre-push Rust suite was not run for that reason.