Skip to content

fix(config): clear every blank compose forward so data/.env.generated is not shadowed - #1039

Merged
rmyndharis merged 1 commit into
mainfrom
fix/blank-compose-forwards-shadow-generated-env
Aug 1, 2026
Merged

fix(config): clear every blank compose forward so data/.env.generated is not shadowed#1039
rmyndharis merged 1 commit into
mainfrom
fix/blank-compose-forwards-shadow-generated-env

Conversation

@rmyndharis

Copy link
Copy Markdown
Owner

What

docker-compose.yml forwards a variable as - KEY=${KEY:-} so that a real host value reaches the
container. When the operator sets nothing, that line does not omit the variable — it injects it
present and empty. An empty value still occupies process.env, and both lower-priority layers,
the project .env and data/.env.generated, are loaded with dotenv override: false, which refuses
to replace a key that is already present, blank or not.

clearBlankEnv exists to delete those blanks before the file layers load. Its key list had drifted
behind the compose file: eight forwarded variables had no entry, so a value set for any of them in
data/.env.generated was discarded with no error and no warning.

Key Effect of the blank forward
AUTO_START_SESSIONS auto-start stayed off; authenticated sessions never restarted
BODY_SIZE_LIMIT per-request body cap fell back to the 25mb default
API_MASTER_KEY a master key set in the file was not honoured
TRUSTED_PROXIES client-IP resolution fell back to the socket IP
CSP_UPGRADE_INSECURE_REQUESTS the HTTP-only opt-out could not be set from the file
WWEBJS_WEB_VERSION a pinned WhatsApp Web build was not applied
WWEBJS_WEB_VERSION_REMOTE_PATH an operator-hosted HTML template was not applied
WWEBJS_AUTH_TIMEOUT_MS a raised first-boot init wait was not applied

data/.env.generated is not an internal artefact — its first-run header tells operators to "modify
this file directly"
, and saveConfig preserves keys it does not own, so hand-set values persist
across dashboard saves and are expected to apply.

Why it surfaced now

AUTO_START_SESSIONS is the key operators noticed, reported in #981.

In 0.11.1 and earlier the variable had no route into the container at all: there is no env_file:
entry and .env is excluded from the build context. That is why the flag appeared inert across the
0.7–0.11 range regardless of how it was set.

0.12.0 added the compose forward but not the matching clear entry, which relocated the failure rather
than ending it. The blank forward now actively shadows data/.env.generated, so the flag still
resolved to off, SessionService.onApplicationBootstrap returned before querying a single session,
and previously authenticated sessions stayed at disconnected with no engine ever created and a null
lastError.

Changes

  • src/config/env-precedence.ts — the eight missing keys are added to BLANK_SHADOWED_ENV_KEYS. The
    doc comment's rule is corrected: being dashboard-managed was never a second condition, because the
    file is hand-editable. Every ${KEY:-} forward belongs in the list.
  • src/config/env-precedence.spec.ts — two tests:
    • a regression test asserting the resolved feature flag, not just the raw variable: with a blank
      forward and AUTO_START_SESSIONS=true in data/.env.generated, computeFeatureFlags reports
      autoStartSessions: true;
    • an invariant test that parses docker-compose.yml and docker-compose.dev.yml, collects every
      - KEY=${KEY:-} forward and asserts each has a clear-list entry. It is paired with a guard test
      asserting the parser finds a known forward, so a pattern that matched nothing could not make it
      vacuously pass.

Read sites were checked before adding each key: all eight already treat a blank value as unset
(?.trim(), || '', a falsy check, or an exact === 'true' comparison), so clearing the blank
changes nothing for a deployment that sets nothing. It only stops the blank from blocking the file
layers. docker-compose.dev.yml was already fully covered; it is added to the guard so it cannot
drift either.

Verification

Behaviour, on the shipped v0.12.1 image. A green unit test proves the code, not the deployment,
so the mechanism was confirmed end to end against the published container image with a mounted
data/.env.generated containing AUTO_START_SESSIONS=true:

Case Container env Result
A — blank forward -e AUTO_START_SESSIONS= raw="" flag=false — file shadowed
B — control, no forward key absent raw="true" flag=true — file applies
C — blank forward + this fix -e AUTO_START_SESSIONS= raw="true" flag=true — file applies

[Bootstrap] Loading saved configuration from: /app/data/.env.generated is printed in all three
cases, so A does not fail because the file went unread. Case B is the control that separates
"shadowed" from "never loaded".

The premise itself was also confirmed rather than assumed: on a live Compose deployment,
docker inspect shows blank-forwarded keys present with an empty value
(WWEBJS_WEB_VERSION=, TRUSTED_PROXIES=, S3_ENDPOINT=, BODY_SIZE_LIMIT=), and
docker compose config renders them as BODY_SIZE_LIMIT: "". Compose injects the key empty; it does
not omit it.

Tests.

  • Restating the list in a test cannot catch a forward added without its clear entry — that is how this
    drifted. The new test derives the expectation from the compose files instead.
  • Mutation-tested on both arms: adding a - MUTANT_KEY=${MUTANT_KEY:-} line to docker-compose.yml,
    and a - DEV_MUTANT=${DEV_MUTANT:-} line to docker-compose.dev.yml, each fail the invariant test
    naming that key; removing the lines restores green.
  • Both new tests were watched failing before the fix — the regression test on the resolved flag
    (Expected: true, Received: false) and the invariant test listing all eight keys.
  • npm run lint, npm run build, npx tsc --noEmit, npm --prefix dashboard run build clean;
    full Jest suite 251 suites / 4053 tests green.

Not covered here

Two adjacent problems were found while verifying this one and are deliberately left for separate
changes, since neither is fixed by clearing blanks:

  • .env.example ships AUTO_START_SESSIONS=false uncommented, and the setup docs say
    cp .env.example .env. An operator who followed that has a real false at top precedence, which is
    correct precedence but an unhelpful default — and it is one of 19 uncommented blank-forwarded keys in
    that file, each of which pins a dashboard-managed setting on copy.
  • scripts/backup.sh and scripts/restore.sh document app-parity config resolution but read
    process.env only, without the blank-clear or the two file layers.

Closes #981

… is not shadowed

docker-compose.yml forwards a variable as `- KEY=${KEY:-}` so a real host value reaches the
container. With nothing set, that renders an empty value, which still occupies process.env and
blocks the project .env and data/.env.generated layers — both loaded with dotenv override:false,
which will not replace a key that is already present, blank or not.

clearBlankEnv deletes those blanks before the file layers load, but its key list had drifted
behind the compose file. Eight forwarded variables had no entry, so a value set for any of them
in data/.env.generated was discarded with no error: AUTO_START_SESSIONS, BODY_SIZE_LIMIT,
API_MASTER_KEY, TRUSTED_PROXIES, CSP_UPGRADE_INSECURE_REQUESTS, WWEBJS_WEB_VERSION,
WWEBJS_WEB_VERSION_REMOTE_PATH and WWEBJS_AUTH_TIMEOUT_MS.

AUTO_START_SESSIONS is the one operators noticed. In 0.11.1 and earlier it had no route into the
container at all; 0.12.0 added the forward without the clear entry, which relocated the failure
rather than ending it. The flag still resolved to off, SessionService's bootstrap hook returned
before querying a session, and authenticated sessions stayed at disconnected with no engine and a
null lastError.

Every read site already treats a blank value as unset, so clearing the blank changes nothing for a
deployment that sets nothing — it only stops the blank from blocking the file layers.

The clear list is now covered by a test that derives the expected set from docker-compose.yml, so a
forward added without its clear entry fails in CI instead of shipping inert.

Closes #981
@rmyndharis
rmyndharis merged commit 4007f3d into main Aug 1, 2026
8 checks passed
@rmyndharis
rmyndharis deleted the fix/blank-compose-forwards-shadow-generated-env branch August 1, 2026 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: After the update process, it is no longer possible to automatically reconnect to available sessions in WhatsApp Web.js Engine

1 participant