Skip to content

Requires does not check if a variable is set #2243

Closed

Description

@timrulebosch

Description

Requires does not check if a variable is set, it only checks is a variable is "present". As a result, variables which are set to "null/nil" will pass the required check.

Version

3.43.2

Operating system

Linux (WSL)

Experiments Enabled

No response

Example Taskfile

version: '3'
tasks:
  default:
    vars:
      A: null
      B: '{{.B}}'
    env:
      A: '{{.A}}'
      B: '{{.B}}'
      C: '{{.C}}'
    cmds:
      - echo "$A"
      - echo "$B"
      - echo "$C"
    requires:
      #vars: [A, B, C]
      vars: [A, B]

Example output:

$ task
task: [default] echo "$A"

task: [default] echo "$B"

task: [default] echo "$C"

Obviously, none of the variables are set. Swap the comment line on the requires constraint to observe the behavior change.

The related code is here:

_, ok := t.Vars.Get(requiredVar.Name)

... where it is observed that the content of variables is not checked. I have read though the PR for this feature and did not notice any conversation about this scenario. I think the documentation explains the expectation correctly:

List of variable or environment variable names that must be set if this task is to execute and run[period missing]

I appreciate that setting a variable to nil can be considered as being set ... but with how templating works in Task, I think set means set to something other than . For example here there is no difference when A is not set, or set to nil ... the default condition will be taken:

A: '{{.A | default "A"}}'

Activity

  1. added theissue type on May 6, 2025
  2. timrulebosch commented on Jun 4, 2025

    @timrulebosch
    Author

    The fundamental problem behind this is that a variable has no nil representation. This is apparently because the tempting system will raise errors in such cases ... and therefore any nil (null in yaml) value will be set to an empty string. Ok.

    I've developed a fix for that, i.e. the requires feature checks for a "nil" value. That works ... however it introduces a conflict to #1962 and #1962 and #2033 ... which moves the requires check before the task is compiled. Which means tasks like this fail with the fix I developed:

      validation-var-dynamic:
        vars:
          FOO:
            sh: echo "one" ***** not evaluated until _after_ a task is compiled.
        requires:
          vars:
            - name: FOO
              enum: ['one', 'two']

    @vmaerten Do you have any thoughts? As far as I can see, compiling a task is ... doing much more than tempting variables. And so that causes cases like:

    require-before-compile:
        requires:
          vars: [ MY_VAR ]
        cmd: |
          {{range .MY_VAR | splitList " " }}
            echo {{.}}
          {{end}}

    to fail (if task compile is moved before requires checks).

    Ideally I would "detect" the sh portion, or compile variables only before doing the requires check.

  3. timrulebosch commented on Jun 5, 2025

    @timrulebosch
    Author

    I've figured out what was happening and updated the related PR.

  4. CJKay commented on Jan 23, 2026

    @CJKay

    Both "requires defined" and "requires non-empty" are valid preconditions. Updating the default behaviour would be a breaking change, but could requires instead be expanded to support a constrained set of conditions? e.g.:

    requires:
      vars:
        - name: FOO
          condition: defined
        - name: BAR
          condition: non-empty

    A more radical (but significantly more flexible) alternative might be to allow it to evaluate shell or boolean template expressions in the context before vars has been evaluated:

    requires:
      conditions:
        - sh: '{{hasKey . "FOO"}}'
          msg: "`FOO` variable is undefined"
        - sh: '{{not (empty .BAR)}}'
          msg: "`BAR` variable is empty"

    Conceptually, this overlaps near-totally with preconditions, except that requires runs before all variables have been evaluated, whilst preconditions runs after.

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

Metadata

Metadata

Assignees

No one assigned

    Fields

    No fields configured for feature.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions