Skip to content

Boolean inputs are not actually booleans #1483

Closed

Description

@MetRonnie

Describe the bug

Boolean type inputs do not work as expected; they are strings instead of booleans, even when surrounded by ${{ }} (e.g. in a step's if condition).

To Reproduce
Steps to reproduce the behavior:

Run this workflow using the workflow dispatch, with the foo input checkbox not ticked:

name: Thingy

on:
  workflow_dispatch:
    inputs:
      foo:
        description: Whether to foo
        type: boolean
        required: false
        default: false

jobs:
  thingy:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    env:
      FOO: ${{ github.event.inputs.foo }}
    steps:
      - name: Check value
        run: |
          echo "The value is: $FOO"

      - name: Run if foo
        if: ${{ github.event.inputs.foo }}
        run: |
          echo "Foo!"

      - name: Don't run if foo  # Eh, I meant "Run if not foo"
        if: ${{ ! github.event.inputs.foo }}
        run: |
          echo "Foo!"

Expected behavior

When the input is false, the Run if foo step should be skipped , and the Don't run if foo step should run.

Runner Version and Platform

Version of your runner? 2.284.0

OS of the machine running the runner? ubuntu-latest (20.04.3)

What's not working?

The value of github.event.inputs.foo is false, yet the Run if foo step runs and the Don't run if foo step is skipped.

image

Additional context

It is the same for a string input type or boolean input type (https://github.blog/changelog/2021-11-10-github-actions-input-types-for-manual-workflows/).

Only if: ${{ github.event.inputs.foo == 'true' }} works. So the input must be being treated as a string.

This goes against what the documentation says at https://docs.github.com/en/actions/learn-github-actions/expressions#about-expressions:

...evaluate an expression rather than treat it as a string.

${{ <expression> }}

Activity

  1. added a commit that references this issue on Nov 12, 2021
  2. ChristopherHX commented on Nov 15, 2021

    @ChristopherHX
    Contributor

    I guess this is a github service bug, sadly broken by design :(.

    the value of the workflow_dispatch payload is 'false', but both of us are expecting a boolean false and not a string.
    Why does this happen? 'false' is a non empty string, which is truthy.

    ${{ github.event.inputs.foo }}
    ${{ 'false' }}
    ${{ true }}
    

    However this might align to previous workflow_dispatch behavior, all inputs are strings like before.

    This is super inconsistent with reusable workflows workflow_call ( beta ), because type: boolean does mean boolean and not a string like in workflow_dispatch.

    name: called
    on:
      workflow_call:
        inputs:
          x:
            type: boolean
    
    jobs:
      test1:
        runs-on: ubuntu-latest
        steps:
        - run: echo '${{inputs.x}}'
          if: ${{inputs.x}}
    name: caller
    on:
      push:
    jobs:
      test2:
        uses: <owner>/<repo>/.github/workflows/called.yml@<ref>
        with:
          x: false

    image

  3. changed the title [-]Boolean inputs do not work in `if:`[/-] [+]Boolean inputs are not actually booleans[/+] on Dec 2, 2021
  4. solarmosaic-kflorence commented on Dec 10, 2021

    @solarmosaic-kflorence

    I have run into this issue as well, it is tricky to identify and debug. I have just been ensuring I always cast potential boolean values to a string, and always match on the string value.

  5. TingluoHuang commented on Dec 13, 2021

    @TingluoHuang
    Member

    @ericsciple do you have any thoughts on this?

  6. piotrekkr commented on Dec 15, 2021

    @piotrekkr

    Seems like input field type in workflow is only for GitHub to know what UI controls should it use and all inputs are strings... So it seems we should check it like if: ${{ inputs.x == 'true' }}

  7. solarmosaic-kflorence commented on Dec 15, 2021

    @solarmosaic-kflorence

    @piotrekkr it is the same for outputs, for example:

    outputs:
      foo:
        description: "Returns true or false"
        value: ${{ steps.foo.outputs.bar == 'true' }}

    The foo output would be type boolean, like false, but matching on outputs.foo == false doesn't seem to work. So instead I do:

    outputs:
      foo:
        description: "Returns true or false"
        value: "${{ steps.foo.outputs.bar == 'true' }}"

    And then match on outputs.foo == 'true' instead, which works every time.

  8. piotrekkr commented on Dec 16, 2021

    @piotrekkr

    @solarmosaic-kflorence Yeah they should clearly document this behavior it can be really confusing. Maybe there is some documentation mentioning this but I did not stumbled upon this for a year now when working with GitHub...

  9. scottmmjackson commented on Dec 16, 2021

    @scottmmjackson

    This is actually really bad because there's no way to write a workflow such that if this bug is fixed your workflow continues to operate as normal. I can't figure out an expression that returns true only if a variable is not the string 'false' and also not the boolean false, because any boolean test I do will be coercing the argument and returning true absent a literal empty string argument.

  10. ChristopherHX commented on Dec 16, 2021

    @ChristopherHX
    Contributor

    I can't figure out an expression that returns true only if a variable is not the string 'false' and also not the boolean false

    Have you tried ${{fromJSON(github.event.inputs.foo)}} or ${{fromJSON(github.event.inputs.foo)}}? I'm not shure if this 100% does what you expect..
    The trick fromJSON expects a string value, if it receives a boolean it is converted to string false => 'false', true => 'true'. Then fromJSON translates the boolean string back to a real boolean.

    You can also cast the input to a string with ${{format('{0}', github.event.inputs.foo)}} then you always have the boolean as string. Then you could use ${{format('{0}', github.event.inputs.foo) != 'false'}}, this might even work with malformed inputs which aren't valid json.

  11. piotrekkr commented on Dec 17, 2021

    @piotrekkr

    This is actually really bad because there's no way to write a workflow such that if this bug is fixed your workflow continues to operate as normal. I can't figure out an expression that returns true only if a variable is not the string 'false' and also not the boolean false, because any boolean test I do will be coercing the argument and returning true absent a literal empty string argument.

    @scottmmjackson Seems like something like this could work I think (still seems quite ugly):

    ${{ github.event.inputs.foo && github.event.inputs.foo != 'false' }}
    

    should give

    true    && true    != 'false'   => true
    'true'  && 'true'  != 'false'   => true
    false   && false   != 'false'   => false
    'false' && 'false' != 'false'   => false
    

    //EDIT

    Ok seems like it may not work with empty strings because javascript...

    '' && '' != 'false' => ""
    
  12. kagahd commented on Feb 7, 2022

    @kagahd

    I have a similar case by reusing workflows where I want let the caller of the reused workflow decide about continue-on-error

    I found the following workaround, where the input variable type is string instead of boolean which is casted to boolean by fromJSON later on:

    on:
      workflow_call:
        inputs:
          continue-on-error:
            type: string
            required: false
            default: false
    
    jobs:
      my-job:
        name: 'my job'
        runs-on: ubuntu-latest
        env:
          CONTINUE_ON_ERROR: ${{inputs.continue-on-error}}
        steps:
          - uses: actions/checkout@v2
          - name: run foo
            shell: bash
            continue-on-error: ${{ fromJSON(env.CONTINUE_ON_ERROR) }}
    
  13. 105 remaining items

  14. added a commit that references this issue on Feb 7, 2023
  15. dekimsey commented on Mar 24, 2023

    @dekimsey

    We will track a different issue as feature enhancement separately :)

    Hi @ajaykn, which issue will be used to track this behavior? #2238? It looks to be this same issue, but I'm not sure. Would you clarify? I'd like to make sure I'm subscribed to the right ticket and also able to escalate this to our GH liason.

    Thank you!

  16. added a commit that references this issue on Apr 21, 2023
  17. DarrenBishop commented on Sep 6, 2023

    @DarrenBishop

    Having similar issues, variation on a theme:

    name: Build Images
    
    on:
      push:
        ...
      pull_request:
        ...
    
    permissions:
      ...
    
    jobs:
      determine-work:
         ...
      call-build-image:
        needs: determine-work
        strategy:
          matrix:
            image: [api, ui]
            include:
              - image: api
                enabled: ${{ needs.determine-work.outputs.build-api }}
              - image: ui
                enabled: ${{ needs.determine-work.outputs.build-ui }}
        uses: org/repo/.github/workflows/build_image.yaml@same-branch
        with:
          build: ${{ matrix.enabled }}
          #build: ${{ fromJSON(matrix.enabled) }} # <--- fromJSON FTW
          image: ${{ matrix.image }}
          tag: ${{ needs.determine-work.outputs.tag }}
        secrets: inherit
        permissions:
          id-token: write
          contents: read
    

    ...and the called workflow

    name: Build Single Image
    
    on:
      workflow_call:
        inputs:
          build:
            description: 'Flag whether to build the Image'
            required: true
            type: boolean
          image:
            description: 'Image to build: api or ui'
            required: true
            type: string
          tag:
            description: 'Image tag'
            required: true
            type: string
    
    jobs:
      build-and-push:
        if: inputs.build
        ...
    

    Seems the matrix involvement undermines all the above e.g. reverting/coercing all things to strings; I was getting two annotations with the same report:

    The template is not valid. (Line: 187, Col: 14): Unexpected value 'true'
    

    Note no mention of the expected boolean type.

    Also note the annoying hack to workaround the matrix context not being available for use in jobs.<job_id>.if

    The fromJSON trick mentioned above (credit to the appropriate community member) did the trick... it only took 50 odd failed runs of debugging to get here.

  18. markwhitfeld commented on Dec 14, 2023

    @markwhitfeld

    To convert the "boolean" input of a workflow_dispatch to be consumable by the boolean input of a workflow_call I used the following logic:
    ${{ inputs.my-bool == true || inputs.my-bool == 'true' }}
    This will accept a boolean true or the string "true" as input to make it true, anything else is false.
    EDIT: Fixed the error as pointed out by @piotrekkr in the comment below. Thanks! It should have been a || and not &&, and also inputs instead of input. My suggestion above is now correct 🎉 .

  19. piotrekkr commented on Dec 14, 2023

    @piotrekkr

    To convert the "boolean" input of a workflow_dispatch to be consumable by the boolean input of a workflow_call I used the following logic: ${{ input.my-bool == true && input.my-bool == 'true' }} This will accept a boolean true or the string "true" as input to make it true, anything else is false.

    @markwhitfeld You mean ${{ input.my-bool == true || input.my-bool == 'true' }}? Otherwise a variable cannot be bool and string at same time so at least one of conditions will always fail and whole expression will be false.

    //EDIT

    I think you should also use inputs and not input

  20. Kristonitas commented on May 29, 2024

    @Kristonitas

    This isn't happening any more since some time 2023: github/docs@e7a6d02

    Inputs are still strings (when using gh workflow run, but the "boolean" input behaves like an enum with "true" and "false" being the only two options that are later cast to a proper boolean. I imagine numbers could be working same way, but didn't validate that.

    I'm confused about the recent activity referencing this issue. Did the problem reappear at some point?
    image

  21. chkp-sergeyl commented on Jun 10, 2024

    @chkp-sergeyl

    well, this is still not working as expected. putting if: ${{ inputs.SOME_BOOLEAN }} doesn't evaluate booleans.

  22. piotrekkr commented on Jun 10, 2024

    @piotrekkr

    This isn't happening any more since some time 2023: github/docs@e7a6d02

    Inputs are still strings (when using gh workflow run, but the "boolean" input behaves like an enum with "true" and "false" being the only two options that are later cast to a proper boolean. I imagine numbers could be working same way, but didn't validate that.

    I'm confused about the recent activity referencing this issue. Did the problem reappear at some point? image

    @Kristonitas I think those issues you added in screenshot were about output params and not inputs. Maybe outputs were mixed with inputs by some people and those were incorrectly linked to this issue.

  23. hassanalamibmx commented on Jun 10, 2024

    @hassanalamibmx

    well, this is still not working as expected. putting if: ${{ inputs.SOME_BOOLEAN }} doesn't evaluate booleans.

    It's working great for me, can you provide an example?

  24. Kristonitas commented on Jun 10, 2024

    @Kristonitas

    @libermansa
    I remade the test that was posted early in this issue, with results that we expect from bool inputs:
    https://github.com/Kristonitas/ga-bool-input-test
    image
    image

    The scenario that was reported in #1483 (comment) (and other similar tests) is not happening right now

    @piotrekkr
    Thanks for pointing that out

    P. S. The arguments passed between workflows are still serialised as strings afaik (hence you can't use json booleans when using the json input flag echo '{"passed_true": true, "passed_false": false}' | gh workflow run test.yml --json would fail). So seeing strings as output "booleans" could still make sense.

  25. rainabba commented on Jun 10, 2024

    @rainabba

    I found that I needed to use fromJSON() (see: https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson) around my "boolean" params to get them to behave as expected.

  26. sanjacob commented on Aug 14, 2024

    @sanjacob

    Still happens in env at least. I had to use fromJSON

    inputs:
      dev:
        description: "Also add development requirements"
        default: false
        type: boolean
    
    steps:
        - env:
            ARG_DEV: ${{ fromJSON(inputs.dev) && '--dev' || '' }}
          run:  pipenv install $ARG_DEV
          shell: bash
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Service BugBug fix scope to the pipelines service and launch app

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions