Skip to content

wrong handling of empty parameters with empty default value #16866

Description

@camaeel

Pre-requisites

  • I have double-checked my configuration
  • I have tested with the :latest image tag (i.e. quay.io/argoproj/workflow-controller:latest) and can confirm the issue still exists on :latest. If not, I have explained why, in detail, in my description below.
  • I have searched existing issues and could not find a match for this bug
  • I'd like to contribute the fix myself (see contributing guide)

What happened? What did you expect to happen?

This is my WorkflowTemplate:

apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
  generation: 1
  name: terraform-cicd-apply
spec:
  arguments:
    parameters:
    - name: revision
      value: HEAD
    serviceAccountName: runner
    strategy: OnWorkflowDeletion
  entrypoint: main
  serviceAccountName: runner
  templates:
  - name: main
    steps:
    - - arguments:
          parameters:
          - name: terraform-script-repository
            value: git@github.com:camaeel/sample.git
          - name: aws_role_arn
            value: arn:aws:iam::xxx:role/yyyy
          - name: subpath
            value: cicd-terraform
          - name: binary
            value: terraform
          - name: revision
            value: '{{workflow.parameters.revision}}'
          - name: destroy
            value: "false"
        name: call-terraform-basic
        templateRef:
          clusterScope: true
          name: terraform-basic
          template: main

and ClusterWorkflowTemplate:

apiVersion: argoproj.io/v1alpha1
kind: ClusterWorkflowTemplate
metadata:
  name: terraform-basic
spec:
  arguments:
    parameters:
    - name: terraform-script-repository
      value: git@github.com:camaeel/playground.git
    - enum:
      - terraform
      - terragrunt
      - tofu
      name: binary
      value: terraform
    - name: revision
      value: HEAD
    - name: subpath
      value: terraform
    - name: aws_role_arn
      value: ""
    - enum:
      - "true"
      - "false"
      name: destroy
      value: "false"
    - name: init_params
      value: ""
    - name: apply_params
      value: ""
  entrypoint: main
  serviceAccountName: runner
  templates:
  - inputs:
      parameters:
      - name: terraform-script-repository
        value: '{{workflow.parameters.terraform-script-repository}}'
      - name: binary
        value: '{{workflow.parameters.binary}}'
      - name: revision
        value: '{{workflow.parameters.revision}}'
      - name: subpath
        value: '{{workflow.parameters.subpath}}'
      - name: aws_role_arn
        value: '{{workflow.parameters.aws_role_arn}}'
      - name: destroy
        value: '{{workflow.parameters.destroy}}'
      - name: init_params
        value: '{{workflow.parameters.init_params}}'
      - name: apply_params
        value: '{{workflow.parameters.apply_params}}'
    name: main
    steps:
    - - arguments:
          parameters:
          - name: terraform-script-repository
            value: '{{inputs.parameters.terraform-script-repository}}'
          - name: binary
            value: '{{inputs.parameters.binary}}'
          - name: revision
            value: '{{inputs.parameters.revision}}'
          - name: subpath
            value: '{{inputs.parameters.subpath}}'
          - name: aws_role_arn
            value: '{{inputs.parameters.aws_role_arn}}'
          - name: destroy
            value: '{{inputs.parameters.destroy}}'
          - name: init_params
            value: '{{inputs.parameters.init_params}}'
          - name: apply_params
            value: '{{inputs.parameters.apply_params}}'
        name: plan
        template: plan
    - - name: approval
        template: approval
    - - arguments:
          artifacts:
          - from: '{{steps.plan.outputs.artifacts.terraform-plan}}'
            name: terraform-plan
          parameters:
          - name: terraform-script-repository
            value: '{{inputs.parameters.terraform-script-repository}}'
          - name: binary
            value: '{{inputs.parameters.binary}}'
          - name: revision
            value: '{{inputs.parameters.revision}}'
          - name: subpath
            value: '{{inputs.parameters.subpath}}'
          - name: aws_role_arn
            value: '{{inputs.parameters.aws_role_arn}}'
          - name: destroy
            value: '{{inputs.parameters.destroy}}'
          - name: init_params
            value: '{{inputs.parameters.init_params}}'
          - name: apply_params
            value: '{{inputs.parameters.apply_params}}'
        name: apply
        template: apply
        when: ' {{steps.approval.outputs.parameters.approve}}  == YES '
  - inputs:
      artifacts:
      - git:
          depth: 1
          repo: '{{inputs.parameters.terraform-script-repository}}'
          revision: '{{inputs.parameters.revision}}'
          sshPrivateKeySecret:
            key: identity
            name: repo-creds
        name: terraform
        path: /home/terraform
      parameters:
      - name: terraform-script-repository
      - name: binary
      - name: revision
      - name: subpath
      - name: aws_role_arn
      - name: destroy
      - name: init_params
      - name: apply_params
    name: plan
    outputs:
      artifacts:
      - archive:
          none: {}
        artifactGC:
          strategy: OnWorkflowCompletion
        name: terraform-plan
        path: /tmp/tfclientsplan
      - archive:
          none: {}
        name: terraform-plan-txt
        path: /tmp/terraform-change.txt
    script:
      command:
      - sh
      env:
      - name: AWS_ROLE_ARN
        value: '{{inputs.parameters.aws_role_arn}}'
      - name: AWS_WEB_IDENTITY_TOKEN_FILE
        value: /var/run/secrets/kubernetes.io/serviceaccount/token
      - name: AWS_REGION
        value: eu-north-1
      image: ghcr.io/camaeel/workflows-toolbox
      imagePullPolicy: Always
      source: |
        set -ex
        aws sts get-caller-identity
        {{inputs.parameters.binary}} version
        cd /home/terraform/{{inputs.parameters.subpath}}
        # run init with params only when provided
        echo "init params = [{{inputs.parameters.init_params}}]"
        if [ -n "{{inputs.parameters.init_params}}" ]; then
          {{inputs.parameters.binary}} init -input=false {{inputs.parameters.init_params}}
        else
          {{inputs.parameters.binary}} init -input=false
        fi
        # run plan with apply-params only when provided
        if [ -n "{{inputs.parameters.apply_params}}" ]; then
          {{inputs.parameters.binary}} plan -destroy={{inputs.parameters.destroy}} -parallelism=2 -input=false -no-color {{inputs.parameters.apply_params}} -out=/tmp/tfclientsplan >> /tmp/terraform-change.txt
        else
          {{inputs.parameters.binary}} plan -destroy={{inputs.parameters.destroy}} -parallelism=2 -input=false -no-color -out=/tmp/tfclientsplan >> /tmp/terraform-change.txt
        fi
  - inputs:
      artifacts:
      - name: terraform-plan
        path: /tmp/tfclientsplan
      - git:
          depth: 1
          repo: '{{inputs.parameters.terraform-script-repository}}'
          revision: '{{inputs.parameters.revision}}'
          sshPrivateKeySecret:
            key: identity
            name: repo-creds
        name: terraform
        path: /home/terraform
      parameters:
      - name: terraform-script-repository
      - name: binary
      - name: revision
      - name: subpath
      - name: aws_role_arn
      - name: destroy
      - name: init_params
      - name: apply_params
    name: apply
    podSpecPatch: |
      {"containers":[
        {"name":"wait", "env":[
          {"name": "AWS_ROLE_ARN", "value": "{{inputs.parameters.aws_role_arn}}"},
          {"name": "AWS_WEB_IDENTITY_TOKEN_FILE", "value": "/var/run/secrets/kubernetes.io/serviceaccount/token"},
          {"name": "AWS_REGION", "value": "eu-north-1"}
        ]}
      ],
      "initContainers":[
        {"name":"init", "env":[
          {"name": "AWS_ROLE_ARN", "value": "{{inputs.parameters.aws_role_arn}}"},
          {"name": "AWS_WEB_IDENTITY_TOKEN_FILE", "value": "/var/run/secrets/kubernetes.io/serviceaccount/token"},
          {"name": "AWS_REGION", "value": "eu-north-1"}
        ]}
      ]}
    script:
      command:
      - sh
      env:
      - name: AWS_ROLE_ARN
        value: '{{inputs.parameters.aws_role_arn}}'
      - name: AWS_WEB_IDENTITY_TOKEN_FILE
        value: /var/run/secrets/kubernetes.io/serviceaccount/token
      - name: AWS_REGION
        value: eu-north-1
      image: ghcr.io/camaeel/workflows-toolbox
      imagePullPolicy: Always
      source: |
        set -ex
        aws sts get-caller-identity
        {{inputs.parameters.binary}} version
        cd /home/terraform/{{inputs.parameters.subpath}}
        # run init with params only when provided
        if [ -n "{{inputs.parameters.init_params}}" ]; then
          {{inputs.parameters.binary}} init -input=false {{inputs.parameters.init_params}}
        else
          {{inputs.parameters.binary}} init -input=false
        fi
        # run apply with apply-params only when provided
        if [ -n "{{inputs.parameters.apply_params}}" ]; then
          {{inputs.parameters.binary}} apply -destroy={{inputs.parameters.destroy}} -auto-approve -input=false -parallelism=2 -no-color {{inputs.parameters.apply_params}} /tmp/tfclientsplan
        else
          {{inputs.parameters.binary}} apply -destroy={{inputs.parameters.destroy}} -auto-approve -input=false -parallelism=2 -no-color /tmp/tfclientsplan
        fi
  - inputs:
      parameters:
      - default: "NO"
        description: Choose YES to continue workflow and deploy to production
        enum:
        - "YES"
        - "NO"
        name: approve
    name: approval
    outputs:
      parameters:
      - name: approve
        valueFrom:
          supplied: {}
    suspend:
      duration: 4h

Now when I submit WorkflowTemplate with defaults inputs/parameters it prints out:

time=2026-09-04T20:38:44.854Z level=INFO msg="waiting for signals" argo=true signalPath=/var/run/argo/ctr/main/signal
+ aws sts get-caller-identity
{
    [REDACTED]
}
+ terraform version
Terraform v1.16.0
on linux_arm64
Your version of Terraform is out of date! The latest version
is 1.16.1. You can update by downloading from https://developer.hashicorp.com/terraform/install
+ cd /home/terraform/cicd-terraform
+ echo 'init params = [{{workflow.parameters.init_params}}]'
+ '[' -n '{{workflow.parameters.init_params}}' ]
init params = [{{workflow.parameters.init_params}}]
+ terraform init '-input=false' '{{workflow.parameters.init_params}}'
╷
│ Error: No positional arguments are expected
│ 
│ The init command does not expect any positional arguments. Did you mean to
│ use -chdir?
╵
time=2026-09-04T20:38:49.861Z level=INFO msg="sub-process exited" argo=true error="exit status 1"
time=2026-09-04T20:38:49.860Z level=INFO msg="file signal handler exiting due to context cancellation" argo=true
time=2026-09-04T20:38:49.876Z level=WARN msg="cannot save artifact" argo=true srcPath=/tmp/tfclientsplan error="stat /tmp/tfclientsplan: no such file or directory"
time=2026-09-04T20:38:49.877Z level=WARN msg="cannot save artifact" argo=true srcPath=/tmp/terraform-change.txt error="stat /tmp/terraform-change.txt: no such file or directory"
Error: exit status 1

problem is that if I don't set init_params, echo prints:

init params = [{{workflow.parameters.init_params}}]

but if I create another WorkflowTemplate where init_params is set it works as expected. If it is not passed explicitly

Version(s)

v4.1.2

Paste a minimal workflow that reproduces the issue. We must be able to run the workflow; don't enter a workflow that uses private images.

metadata:
  name: terraform-cicd-apply
spec:
  templates:
    - name: main
      inputs: {}
      outputs: {}
      metadata: {}
      steps:
        - - name: call-terraform-basic
            arguments:
              parameters:
                - name: terraform-script-repository
                  value: git@github.com:camaeel/infra.git
                - name: aws_role_arn
                  value: arn:aws:iam::xxxx:role/YYYY
                - name: subpath
                  value: cicd-terraform
                - name: binary
                  value: terraform
                - name: revision
                  value: "{{workflow.parameters.revision}}"
                - name: destroy
                  value: "false"
            templateRef:
              name: terraform-basic
              template: main
              clusterScope: true
  entrypoint: main
  arguments:
    parameters:
      - name: revision
        value: HEAD
  serviceAccountName: runner
  artifactGC:
    strategy: OnWorkflowDeletion
    serviceAccountName: runner
    podSpecPatch: >
      {"containers":[
        {"name":"main", "env":[
          {"name": "AWS_ROLE_ARN", "value": "arn:aws:iam::xxxx:role/yyyy"},
          {"name": "AWS_WEB_IDENTITY_TOKEN_FILE", "value": "/var/run/secrets/kubernetes.io/serviceaccount/token"},
          {"name": "AWS_REGION", "value": "eu-north-1"}
        ]}
      ]}

Logs from the workflow controller

❯ kubectl logs -n argo-workflows deploy/argo-workflows-workflow-controller | grep terraform-cicd-apply-mlwrj
Found 2 pods, using pod/argo-workflows-workflow-controller-6868d66cf8-b4fm2

Logs from in your workflow's wait container

kubectl logs -n argo -c wait -l workflows.argoproj.io/workflow=${workflow},workflow.argoproj.io/phase!=Succeeded

Activity

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions