Skip to content

fix: resolve environment variables on application rollback - #4923

Open
dmtrTm wants to merge 1 commit into
Dokploy:canaryfrom
dmtrTm:fix/rollback-environment-variables
Open

fix: resolve environment variables on application rollback#4923
dmtrTm wants to merge 1 commit into
Dokploy:canaryfrom
dmtrTm:fix/rollback-environment-variables

Conversation

@dmtrTm

@dmtrTm dmtrTm commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What is this PR about?

Rolling back an application whose env references environment-scoped variables (e.g. ${{environment.FOO}}) always failed with Invalid environment variable: environment.FOO, surfaced to the client as an opaque HTTP 400 "Error input: Rolling back". Regular deployments resolve those variables correctly.

rollbackApplication() was missing the third parameter when calling prepareEnvironmentVariables():

// Before - missing environment.env parameter
const envVariables = prepareEnvironmentVariables(
	env,
	fullContext.environment.project.env,
);

// After - now includes environment.env
const envVariables = prepareEnvironmentVariables(
	env,
	fullContext.environment.project.env,
	fullContext.environment.env,
);

This completes the rollout started in fb749cd, which added the third argument to every other call site (all six databases, the builders, compose) but left services/rollbacks.ts, which had been calling the helper since 24bff96. It was the last remaining two-argument caller in the repo.

The value is already captured in the snapshot - createRollback() stores the result of findApplicationById(), which loads environment: { with: { project: true } } - it was simply never passed to the resolver. Both fullContext declarations (the local one in rollbackApplication() and the jsonb().$type<>() annotation on the rollback table) typed environment as { project: Project } without env, which is why the missing argument was invisible to the compiler; both are widened to Environment & { project: Project }.

No schema change, no migration, no backfill: existing snapshots already contain the value, so this also repairs rollbacks stored by earlier versions. Snapshots that predate the environment tables keep today's exact behaviour - parse(undefined ?? "") yields the same empty map, and the same error. Both scope arguments come from the snapshot rather than the live rows, consistent with the rest of rollbackApplication() (service env, project env, mounts, ports and resources all come from the snapshot).

How this was verified

Local Dokploy dev instance (v0.29.13, single-node swarm), application on the Docker provider with NODE_ENV=${{environment.NODE_ENV}} plus a marker variable, an environment-level NODE_ENV=production, and rollbacks enabled against a local registry. Two deployments produced :v1 (nginx:alpine, APP_MARKER=v1) and :v2 (nginx:1.27-alpine, APP_MARKER=v2), then Rollback to :v1:

Before - HTTP 400 {"message":"Error input: Rolling back","code":"BAD_REQUEST","zodError":null}, with the real cause only in the backend log:

Error: Invalid environment variable: environment.NODE_ENV
    at prepareEnvironmentVariables (packages/server/src/utils/docker/utils.ts:408)
    at rollbackApplication (packages/server/src/services/rollbacks.ts:274)

The swarm service was left untouched (still nginx:1.27-alpine) - the throw happens before service.update().

After - HTTP 200, and the swarm service was updated:

IMAGE: localhost:5001/testuser/rollback-demo-xxxxxx:v1
ENV:   ["NODE_ENV=production","APP_MARKER=v1"]

NODE_ENV resolves from the environment scope, and APP_MARKER=v1 comes from the v1 snapshot rather than the live value, confirming the snapshot semantics.

Note for reproducing on current canary: rollback now fails even earlier, in findRollbackById(), with PostgresError: cannot pass more than 100 arguments to a function (54023) - migration 0175_fantastic_peter_quill.sql took application to 101 columns, and drizzle's nested relational query builds a json_build_array() above Postgres' FUNC_MAX_ARGS limit of 100. That is a separate issue (I am happy to open one); the verification above narrows that one query locally so the rollback path is reachable. On released versions (<= v0.29.13, 99 columns) the bug in this PR reproduces directly.

Checklist

Before submitting this PR, please make sure that:

Issues related (if applicable)

Same class of bug as #3452 / #3457, which fixed the Stack compose path.

Screenshots (if applicable)

N/A - Backend logic change, verified end to end as described above.

rollbackApplication() called prepareEnvironmentVariables() without the
environment env, so every ${{environment.*}} reference threw "Invalid
environment variable: environment.X" and the rollback failed with an
opaque 400 before the swarm service was updated.

fb749cd added the third argument to every other call site but left
services/rollbacks.ts, which had been calling the helper since 24bff96.
The value is already captured in the snapshot by createRollback(); both
fullContext declarations simply typed environment as { project: Project },
so the missing argument was invisible to the compiler.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@dmtrTm
dmtrTm requested a review from Siumauricio as a code owner July 28, 2026 08:29
@dosubot dosubot Bot added size:XS This PR changes 0-9 lines, ignoring generated files. bug Something isn't working labels Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:XS This PR changes 0-9 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant