Skip to content

Regression in 3.49.0: global vars can be resolved before dotenv is loaded, causing fallback to override dotenv value #2722

Closed

Description

@winterTTr

Description

There appears to be a regression in Task 3.49.0 related to the interaction between global vars and dotenv.

With the Taskfile below, Task 3.48.0 resolves IMAGE_TAG from the dotenv file and prints XXXX, but Task 3.49.0 resolves the fallback default and prints ABC.

This looks like global vars are being resolved too early, before dotenv values are merged into the taskfile environment.

Analysis
The behavior seems to come from a change in the variable resolution flow introduced by commit:

2cdd7d3

Commit message:

fix: Call ReplaceVars() to resolve Ref's for imported global vars. (#2632)

The likely sequence is:

During setup, Task reads dotenv files by first calling GetTaskfileVariables().

In 3.49.0, GetTaskfileVariables() now calls ReplaceVars() on c.TaskfileVars and writes the resolved values back into the compiler state.

That causes this global var to be resolved too early:

At that moment, the dotenv file has not yet been merged into the environment, so the expression resolves to ABC.

Later, dotenv is loaded, but the stored global var has already been rewritten to the fallback value, so task execution still sees ABC.

In 3.48.0, this early mutation did not happen, so once dotenv was merged, task compilation could still resolve IMAGE_TAG to XXXX.

Why This Looks Like a Regression
This changes previously working behavior for a valid configuration pattern:

Before 3.49.0: global vars could still observe values coming from global dotenv files
In 3.49.0: the same global vars can become fixed to their fallback values before dotenv is applied
That makes the behavior externally incompatible across versions.

Suspected Fix Direction
A likely fix would be to avoid mutating stored global taskfile vars during the early GetTaskfileVariables() phase, or otherwise ensure dotenv values are available before global vars are permanently resolved.

Notes
This seems related to the imported global Ref fix from #2632, but the change also affects dotenv-backed global var resolution.

Version

3.49.0

Operating system

both linux and mac os

Experiments Enabled

No response

Example Taskfile

version: '3'


vars:
  IMAGE_TAG: '{{ .IMAGE_TAG | default "ABC" }}'

dotenv:
- Taskfile.env

tasks:
  test:
    cmds:
    - echo "{{.IMAGE_TAG}}"



# > cat Taskfile.env
# IMAGE_TAG=XXXX

Activity

  1. changed the title [-]Regression on 3.49.0 - var defined in .env cannot be resolved as expected value during global var define[/-] [+]Regression in 3.49.0: global vars can be resolved before dotenv is loaded, causing fallback to override dotenv value[/+] on Mar 8, 2026
  2. trulede commented on Mar 8, 2026

    @trulede
    Contributor

    Is this a duplicate of #2720 ? There is a PR that can be tried ...

    readDotEnvFiles() is calling e.Compiler.GetTaskfileVariables(), which triggers the problem area, and then resolves the envs that it itself loads.

    I could image two solutions:

    1/ Further restrict the problematic call to templater.ReplaceVars() to only GetVariables() or FastGetVariables() and not GetTaskfileVariables().

    2/ Change the logic in readDotEnvFiles() to get the order (possibly) correct ... load, merge and then template. Why does templating even occur here? To expand envars in the read dotenv vars? Is that necessary here or can be be done later.

  3. added and removed on Mar 8, 2026
  4. andreynering commented on Mar 8, 2026

    @andreynering
    Member

    Thank you for reporting!

    We reverted #2632 for now and we're releasing v3.49.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions