QA cannot start: UPLOADS_DIR became required in #64 but the compose file never set it #107

Closed
opened 2026-08-21 17:23:28 -05:00 by bermudalamb · 0 comments
Owner

The QA container refuses to boot:

[config] refusing to start — 1 problem(s) with the environment:
[config]   - UPLOADS_DIR is required and is not set.

What happened

#64 added UPLOADS_DIR to the always-required list, on the reasoning that its fallback of /app/uploads is correct inside the container and wrong everywhere else, so nothing should inherit it silently. That reasoning stands.

What was missed is that docker-compose.qa.yml never set it either. QA had always relied on exactly the fallback #64 set out to stop people relying on. So the first deploy after #64 merged is the first one that fails.

This was an incomplete check on my part, and specifically a check that looked confident. #64's verification confirmed both CI workflows set every always-required variable, and reported that — but CI is not what deploys. The compose file, which is, was never looked at.

The second half: setting it in the Portainer stack does not help

ADMIN_GATE_SECRET was added to the stack's environment variables and the container still reports it unset. That is not a mistake — it is how compose works, and it is the same mechanism #87 already documented:

Compose only forwards variables explicitly declared in environment:.

Portainer's stack variables are available for interpolation into the compose file as ${VAR}. They are not handed to the container. A service receives exactly what its environment: block lists, and nothing else.

So both variables need a line in the compose file, and they need different treatment:

Variable Line Why
UPLOADS_DIR UPLOADS_DIR=/app/uploads Not a secret, and it must match the right-hand side of the volume mapping. Hardcoded so it cannot drift from the mount.
ADMIN_GATE_SECRET ADMIN_GATE_SECRET=${ADMIN_GATE_SECRET} A secret, so the value stays in the stack environment and only the reference lives in the repo.

The header comment listing required stack variables needs ADMIN_GATE_SECRET added too, since it is now one of them.

Production is exposed to the same failure

Production runs from a Portainer stack outside this repository and has the same history — it will have been relying on the /app/uploads fallback as well. It will refuse to boot on its next rebuild unless UPLOADS_DIR is set there first. That is not fixed by this change, and it should be done before the next production deploy rather than discovered during one.

The wider lesson worth recording

#64's checks answered "does CI still pass" when the question that mattered was "will this still deploy". Those are different questions, and a required-configuration change is precisely the case where the second one is the one to ask. Any future change to the always-required list should be checked against docker-compose.qa.yml and the production stack, not just the workflows.

Verification

docker compose -f docker-compose.qa.yml config renders both variables with the expected values, and the QA container boots with no [config] refusing to start line — and, since ADMIN_GATE_SECRET will now be present, without the admin-gate warning either.

Severity

High while it stands. QA is down and production is one rebuild away from the same.

The QA container refuses to boot: ``` [config] refusing to start — 1 problem(s) with the environment: [config] - UPLOADS_DIR is required and is not set. ``` ## What happened #64 added `UPLOADS_DIR` to the always-required list, on the reasoning that its fallback of `/app/uploads` is correct inside the container and wrong everywhere else, so nothing should inherit it silently. That reasoning stands. What was missed is that **`docker-compose.qa.yml` never set it either.** QA had always relied on exactly the fallback #64 set out to stop people relying on. So the first deploy after #64 merged is the first one that fails. This was an incomplete check on my part, and specifically a check that looked confident. #64's verification confirmed both CI workflows set every always-required variable, and reported that — but CI is not what deploys. The compose file, which is, was never looked at. ## The second half: setting it in the Portainer stack does not help `ADMIN_GATE_SECRET` was added to the stack's environment variables and the container still reports it unset. That is not a mistake — it is how compose works, and it is the same mechanism #87 already documented: > Compose only forwards variables explicitly declared in `environment:`. Portainer's stack variables are available for **interpolation into the compose file** as `${VAR}`. They are not handed to the container. A service receives exactly what its `environment:` block lists, and nothing else. So both variables need a line in the compose file, and they need different treatment: | Variable | Line | Why | | --- | --- | --- | | `UPLOADS_DIR` | `UPLOADS_DIR=/app/uploads` | Not a secret, and it must match the right-hand side of the volume mapping. Hardcoded so it cannot drift from the mount. | | `ADMIN_GATE_SECRET` | `ADMIN_GATE_SECRET=${ADMIN_GATE_SECRET}` | A secret, so the value stays in the stack environment and only the reference lives in the repo. | The header comment listing required stack variables needs `ADMIN_GATE_SECRET` added too, since it is now one of them. ## Production is exposed to the same failure Production runs from a Portainer stack outside this repository and has the same history — it will have been relying on the `/app/uploads` fallback as well. **It will refuse to boot on its next rebuild** unless `UPLOADS_DIR` is set there first. That is not fixed by this change, and it should be done before the next production deploy rather than discovered during one. ## The wider lesson worth recording #64's checks answered "does CI still pass" when the question that mattered was "will this still deploy". Those are different questions, and a required-configuration change is precisely the case where the second one is the one to ask. Any future change to the always-required list should be checked against `docker-compose.qa.yml` and the production stack, not just the workflows. ## Verification `docker compose -f docker-compose.qa.yml config` renders both variables with the expected values, and the QA container boots with no `[config] refusing to start` line — and, since `ADMIN_GATE_SECRET` will now be present, without the admin-gate warning either. ## Severity High while it stands. QA is down and production is one rebuild away from the same.
bermudalamb added reference feature/107-compose-required-env 2026-08-21 17:38:54 -05:00
bermudalamb self-assigned this 2026-08-21 17:39:08 -05:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bermudalamb/redefined-designs#107