runner icon indicating copy to clipboard operation
runner copied to clipboard

Setting strategy.matrix.value to expression throws invalid type error

Open pakalas opened this issue 3 years ago • 27 comments

Getting "Invalid type found: array was expected but string was found" at matrix: value: ${{fromJson(needs.setup.outputs.matrix)}}

Any ${{}} expression fails. Only [] is allowed now, with at least one value. But the value cannot be an expression.

`name: Test Matrix

on: workflow_dispatch:

jobs:

setup: runs-on: ubuntu-latest outputs: matrix: ${{ steps.matrix.outputs.value }} steps: - id: matrix run: | echo '::set-output name=value::["a", "b", "c"]' build: needs: [ setup ] runs-on: ubuntu-latest strategy: matrix: value: ${{fromJson(needs.setup.outputs.matrix)}} steps: - run: | echo "${{ matrix.value }}"`

pakalas avatar Feb 04 '22 12:02 pakalas

Related: https://github.com/actions/runner/issues/751

pakalas avatar Feb 04 '22 12:02 pakalas

Hi @pakalas,

Thanks for opening this issue and relating it to the previous one. We will try to reproduce it to understand the cause of the issue and we will get back to you as soon as possible!

nikola-jokic avatar Feb 04 '22 13:02 nikola-jokic

Hi @pakalas,

Could you please tell me, if you commit your workflow with the "syntax error", does the action start? In other words, a syntax error is shown in the editor, but when it is committed, actions specified by the "invalid" YAML are performed?

When I reproduced it, actions were executed. The only problem was that, while editing the file in-browser editor, a syntax error was shown, but after committing it, the workflow was executed without problems.

Can you please tell me if that is the case with your workflow as well?

nikola-jokic avatar Feb 07 '22 10:02 nikola-jokic

@nikola-jokic The same issue I too get, the editor shows syntax error but after commiting the file actions execute and workflow fails with error as below:

ERROR when evaluating ‘strategy’ for ‘Test-Actions’. .github/workflows/main.yml (Line:33, col: 15): Unexpected type of value ‘false’, expected type: Mapping.

ag-monk avatar Feb 08 '22 11:02 ag-monk

Hi @ag-monk,

Could you please provide an example of your workflow file so I can take a look? While investigating this, I used workflow file:

name: build
on: push
jobs:
  job1:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.value }}
    steps:
      - id: set-matrix
        run: echo "::set-output name=value::['a','b','c']"
  job2:
    needs: job1
    runs-on: ubuntu-latest
    strategy:
      matrix:
        value: ${{fromJSON(needs.job1.outputs.matrix)}}
    steps:
      - run: echo "${{ matrix.value }}"

Also, please keep in mind this example: https://docs.github.com/en/actions/learn-github-actions/expressions#example-returning-a-json-object.

Both of them worked so there might be some issues within your definition that are causing this syntax error.

nikola-jokic avatar Feb 08 '22 11:02 nikola-jokic

Hi everyone,

Since there is no response for a while, and this does not seem to be a runner error, I will now close this issue. And about this red underline inside the in-browser editor, please post this to GitHub Community Support Forum, which is actively monitored. Using the forum ensures that we route your problem to the correct team.

nikola-jokic avatar Feb 21 '22 08:02 nikola-jokic

Im fighting with this as well. If I change matrix.regions over to the output of my script, it works. If I leave the output of the regions variable from the last job, it errors out. It seems it does not like it when wrapped in single quotes?

[Pre-Setup : .github#L1] Error when evaluating 'strategy' for job 'Deploy-ECR'. (Line: 45, Col: 18): Unexpected value '[us-east-1, us-east-2, us-west-2]'

strategy: matrix: regions: ${{ needs.Pre-Setup.outputs.regions }}

bragdonjm avatar Mar 03 '22 16:03 bragdonjm

Hi @bragdonjm,

I am not sure if I understand you correctly, but if an array is being wrapped around with the ('), that makes it a string, which is not an expected type. But if I did not understand you correctly, could you please provide me with an example, so I can look at it?

nikola-jokic avatar Mar 04 '22 10:03 nikola-jokic

Hello @nikola-jokic Thanks for the response. No matter how I controlled the output, and modified the echo, it's like actions is wrapping the single quote not the thing producing the output. The only way I found around this was to change the return into Jason and import the matrix from Jason.

bragdonjm avatar Mar 04 '22 12:03 bragdonjm

For sure, you are completely right. Because of it, you should always use fromJSON. We have a similar situation with declaring booleans in inputs. They will be treated as strings, so fromJSON is there to help you parse it to the data type which will be accepted.

nikola-jokic avatar Mar 04 '22 12:03 nikola-jokic

@nikola-jokic thanks for the fast responses. I hope someone finds these posts after spending some time searching and trial and error and figures out fromJSON is the key! thanks!

bragdonjm avatar Mar 04 '22 13:03 bragdonjm

Hi @bragdonjm,

I will file an issue and a PR in the future, updating the docs to help with this problem 😊

nikola-jokic avatar Mar 04 '22 13:03 nikola-jokic

I'm getting the invalid type error when attempting to add the example:

Invalid type found: object was expected but string was found

jobs:
  job1:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
    - id: set-matrix
      run: echo "::set-output name=matrix::{\"include\":[{\"project\":\"foo\",\"config\":\"Debug\"},{\"project\":\"bar\",\"config\":\"Release\"}]}"

  job2:
    needs: job1
    runs-on: ubuntu-latest
    strategy:
      matrix: ${{fromJson(needs.job1.outputs.matrix)}}
    steps:
    - run: echo hello

bskiefer avatar Apr 22 '22 16:04 bskiefer

Yeah, its the nested bracket I think. There is probably a better way to do it but the way I handle it right now is generate a map in a flat plane and repeat it within the matrix. I cannot remember if its a listed set of maps or just straight maps. so either: [{"Name" : "Jeff", "Age": "109"}, {"Name": "John", "Age": "42"}] or just {"Name" : "Jeff", "Age": "109"}, {"Name": "John", "Age": "42"}. This would run two instances of Job2 both with access with the matrixed data. If you want a better example shoot me a contact.

bragdonjm avatar Apr 22 '22 17:04 bragdonjm

@bragdonjm I have a job that pulls PR from github and sorts them into different types of prs based on their labels. I am trying to get the values into an object that I can parse through in job2

I keep getting 1 of several syntax errors....either unexpected value string, or unexpected token ':' Here is job1. The commented out echo commands at the bottom are different ways I have tried to extract the values I need

job1:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.fetch-branch-names.outputs.values}}
    steps:
      - name: Fetch branch names
        id: fetch-branch-names
        uses: actions/github-script@v6
        with:
          github-token: ${{secrets.GITHUB_TOKEN}}
          script: |
            const pulls = github.paginate call to my repo to return the prs.


            const uiBranches=[];
            const apiBranches = [];
            let uiPrs = [];
            let apiPrs=[];

            for (const pull of pulls) {
              const branch = pull['head']['ref'];
              let isUIPr = false
              let isAPIPr = false
              for (const label of pull.labels){
                if(label.name == 'component:ui'){
                  isUIPr = true
                }
                if(label.name == 'component:api'){
                  isAPIPr = true
                }
              }
              if (branch.startsWith('dependabot')) {
                if(isUIPr){
                  uiBranches.push(branch)
                  uiPrs.push('#' + pull['number'] + ' ' + pull['title']);
                }

                if(isAPIPr){
                  apiBranches.push(branch)
                  apiPrs.push('#' + pull['number'] + ' ' + pull['title']);
                }
              }
            }

            if (uiBranches.length == 0  && apiBranches.length == 0) {
              core.setFailed('No PRs/branches matched criteria');
              return;
            }


            const uiPrStrings = uiPrs.join('\n')
            const apiPrStrings = apiPrs.join('\n')
            const uiCombinedBranches = uiBranches.join(' ')
            const apiCombinedBranches = apiBranches.join(' ')


        # echo '::set-output name=values::{\"values\":[{\"branches\": $uiCombinedBranches, \"prStrings\": $uiPrStrings, \"combinedBranchName\": \"UIDependencyUpgrade\",\"label\": \"component:ui\"}, {\"branches\": $apiCombinedBranches, \"prStrings\": $apiPrStrings, \"combinedBranchName\": \"APIDependencyUpgrade\", \"label\":\"component:api\"}]}'

        # core.setOutput('values', [{branches: uiCombinedBranches, prStrings: uiPrStrings, combinedBranchName: 'UIDependencyUpgrade',label: "component:ui"}, {branches: apiCombinedBranches, prStrings: apiPrStrings, combinedBranchName: 'APIDependencyUpgrade', label:"component:api"}])

Any ideas here?

AlexSCorey avatar Apr 26 '22 20:04 AlexSCorey

@bskiefer it works fine if you pull out the include: key from your manual json. e.g.

jobs:
  job1:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
    - id: set-matrix
      run: echo "::set-output name=matrix::[{\"project\":\"foo\",\"config\":\"Debug\"},{\"project\":\"bar\",\"config\":\"Release\"}]"

  job2:
    needs: job1
    runs-on: ubuntu-latest
    strategy:
      matrix: 
        include: ${{fromJson(needs.job1.outputs.matrix)}}
    steps:
    - run: echo hello

snowe2010 avatar May 07 '22 00:05 snowe2010

I am trying the exact sample on the doc here but looks like it matrix is not picking up the json abject.

image

ashish-raj-wenovate avatar May 17 '22 11:05 ashish-raj-wenovate

Yes I am also facing the same problem as [ashish-raj-wenovate] faced.

satheeshcvcet avatar May 23 '22 04:05 satheeshcvcet

Hi @nikola-jokic i also hit this problem and all examples in this issue like you mention in comment or from doc fail with error Invalid type found: array was expected but string was found

can you reopen this issue thanks

filipagh avatar Jul 22 '22 12:07 filipagh

hi,

seems to be a bug and it did fail until I rewrote every line manually with all the correct indentations and spaces
also i found out that if you copy-paste it from somewhere it does not run seems to me that there are hidden chars while copypasting

i ignored the error 'invalid type found: array was expected but string was found' and continued it might a case of incorrect indentations and spaces , not sure, if so its a bug for sure.

still error should not appear while editing

my account.txt file is:

1111111 2222222

jobs:
  list-manifests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - id: set-matrix
        run: echo "::set-output name=matrix::$(cat accounts.txt | jq -R -s -c 'split("\n")[:-1]')"
    outputs:
       matrix: ${{ steps.set-matrix.outputs.matrix }}
  

  check:
    needs: [list-manifests]
    runs-on: ubuntu-latest
    strategy:
      matrix: 
        manifest: ${{ fromJson(needs.list-manifests.outputs.matrix) }}
    steps:
      - name: test
        run: |
          echo ${{ matrix.manifest }}
        shell: bash

gfrid avatar Jul 24 '22 18:07 gfrid

I was getting this error, and found this: https://github.com/orgs/community/discussions/26284#discussioncomment-3251198

It seems like you need to remove all line breaks and spaces in the output.

Not Working -

clouds=$(cat config.json | jq '.cloudNickname' | jq 'keys')

Working -

clouds=$(echo $(cat config.json | jq '.cloudNickname' | jq 'keys' ) | sed 's/ //g')

erick-prosimo avatar Sep 12 '22 15:09 erick-prosimo


CI: .github#L1
Error when evaluating 'strategy' for job 'matrix-job'. .github/workflows/changed.yaml (Line: 25, Col: 15): Unexpected type of value '{"chart":["http-headers"]}', expected type: Mapping.

What's wrong? Looks like Mapping to me.

Unexpected type of value '{"chart":["http-headers"]}', expected type: Mapping.

bukowa avatar Oct 12 '22 17:10 bukowa

This was driving me crazy, originally I was using cat and jq together to get the content into a string: cat releases.json | jq 'tostring' and then adding it to the GITHUB_OUTPUT:

echo "matrix=$(cat releases.json | jq 'tostring')" >> $GITHUB_OUTPUT

but when I ran the workflow I always got this error:

Unexpected type of value '[{"name":"XXX","ip_address":"XXX"},{"name":"XXX","ip_address":"XXX"}]', expected type: Sequence.

Note: I've been using the include property when defining the matrix.

Anyways, for some reason a pair of single quotes were added even removing with sed threw another error message:

Error parsing fromJson,.github/workflows/XXX.yaml (Line: 164, Col: 18): Invalid property identifier character: \. Path '[0]', line 1, position 2.,.github/workflows/XXX.yaml (Line: 164, Col: 18): Unexpected type of value '', expected type: Sequence.

The solution that I found was to use a multiline string, e.g.:

    steps:
      - name: Get JSON content
        id: get-json-content
        run: |
          echo 'JSON_CONTENT<<EOF' >> $GITHUB_OUTPUT
          cat releases.json >> $GITHUB_OUTPUT
          echo 'EOF' >> $GITHUB_OUTPUT
    outputs:
      new_content: ${{ steps.get-json-content.outputs.JSON_CONTENT }} 

Job using matrix:

  matrix_job_test:
    name: Matrix job test
    runs-on: ubuntu-latest
    needs: test_job
    strategy:
      matrix:
        include: ${{ fromJSON(needs.test_job.outputs.new_content) }}
    steps:
      - run: |
          echo $STACK_NAME
          echo $STACK_IP
        env:
          STACK_NAME: ${{ matrix.name }}
          STACK_IP: ${{ matrix.ip_address }}

In case someone wonder, this is the JSON content structure:

[
  {
  "name": "string",
  "ip_address": "string"
  },
  {
    "name": "string",
    "ip_address": "string"
  }
]

I hope this helps other people, cheers!

javierlga avatar Dec 20 '22 16:12 javierlga

I have been looking around for this issue for a couple of days now. This works but have to use this bodge as workaround. Thanks so much javierlga Javier Lizarraga

amrit-loksom avatar Jan 09 '23 12:01 amrit-loksom

I used this to grab only unique directories from changed actions

changed-files:
  runs-on: ubuntu-latest
  name: Test changed-files
  outputs:
    matrix: ${{ steps.set-matrix.outputs.matrix }}
    any_changed: ${{ steps.changed-files-specific.outputs.any_changed }}
  steps:
    - uses: actions/checkout@v3
      with:
        fetch-depth: 0

    - name: Check changed charts
      id: changed-files-specific
      uses: tj-actions/[email protected]
      with:
        files: |
          charts/**
        json: true

    - id: set-matrix
      if: steps.changed-files-specific.outputs.any_changed == 'true'
      run: |
        set -eux
        DATA=$(echo ${{ steps.changed-files-specific.outputs.all_changed_files }} | jq -c '. | map(split("/")[1]) | unique')
        echo "matrix=$DATA" >> "$GITHUB_OUTPUT"

bukowa avatar Jan 09 '23 15:01 bukowa

Is there any intention to fix this or make the documentation on it intuitive at all?

I don't even see how this got into general availability. It's clearly barely been tested

mohas556 avatar Jan 12 '23 16:01 mohas556

I found a fix: you need to add [ ' *** ' ]

    steps:
   - id: Log
     run: |
          echo "matrix=['$input']" >> $GITHUB_OUTPUT
     env:
          input: ${{ github.event.inputs.platform }}

MikaelStudios avatar Jan 22 '23 10:01 MikaelStudios

I'm having the same issue.

Error when evaluating 'strategy' for job 'disable-replication'. .github/workflows/deploy.yml : Error parsing fromJson,.github/workflows/deploy.yml : Error reading JToken from JsonReader. Path '', line 0, position 0.,.github/workflows/deploy.yml : Unexpected type of value '', expected type: Sequence.

disable-replication:
  runs-on: ubuntu-latest
  strategy:
    matrix:
      server: ${{ fromJson(vars.SERVERS_JSON) }}
  steps:
    - name: Hello world
      run: echo ${{ matrix.server.name }}
My SERVERS_JSON variable looks like this:
[
  {
    "name": "backend",
    "host": "backend.example.com",
    "user": "www-example"
  },
  {
    "name": "frontend-a",
    "host": "frontend-a.example.com",
    "user": "www-example"
  },
  {
    "name": "frontend-b",
    "host": "frontend-b.example.com",
    "user": "www-example"
  }
]

I also tried to change it to a oneliner JSON:

[{"name":"backend","host":"backend.example.com","user":"www-example"},{"name":"frontend-a","host":"frontend-a.example.com","user":"www-example"},{"name":"frontend-b","host":"frontend-b.example.com","user":"www-example"}]

But that did not resolve it either.


When I change my job to inline the array, everything works fine.

Inlined working example
disable-replication:
  runs-on: ubuntu-latest
  strategy:
    matrix:
      server: [
        {
          "name": "backend",
          "host": "backend.example.com",
          "user": "www-example"
        },
        {
          "name": "frontend-a",
          "host": "frontend-a.example.com",
          "user": "www-example"
        },
        {
          "name": "frontend-b",
          "host": "frontend-b.example.com",
          "user": "www-example"
        }
      ]
  steps:
    - name: Hello world
      run: echo ${{ matrix.server.name }}

Workaround

It seems the workaround mentioned by javierlga works. When you create the matrix json in another job, things work fine.

+create-server-matrix:
+  runs-on: ubuntu-latest
+  outputs:
+    server-matrix: ${{ steps.create-server-matrix.outputs.SERVER_MATRIX }}
+  container: debian:bullseye-slim
+  steps:
+    - name: Install jq
+      run: apt-get update -y && apt-get install -y jq
+
+    - name: Create server matrix
+      id: create-server-matrix
+      env:
+        SERVERS_JSON: ${{ vars.SERVERS_JSON }}
+      run: echo "SERVER_MATRIX=$(echo "$SERVERS_JSON" | jq -r 'tostring')" >> $GITHUB_OUTPUT

disable-replication:
  runs-on: ubuntu-latest
+ needs: [ create-server-matrix ]
  strategy:
    matrix:
-     server: ${{ fromJson(vars.SERVERS_JSON) }}
+     server: ${{ fromJson(needs.create-server-matrix.outputs.server-matrix) }}
  steps:
    - name: Hello world
      run: echo ${{ matrix.server.name }}

RobinHoutevelts avatar Apr 06 '23 13:04 RobinHoutevelts

Took me a bit, but got this working (relevant snippets):

Constructing an array in one job (files here is a newline separated list of files):

    outputs:
      job_files_changed_array: ${{ steps.job_files_changed.outputs.files }}

...

          fmt="$(echo -n "${files}" | paste -sd ',' - | sed -e 's/,/", "/g')"
          echo 'files=["'"${fmt}"'"]' >> "$GITHUB_OUTPUT"

Using the array in another:

    strategy:
      matrix:
        value: ${{ fromJson(needs.changed.outputs.job_files_changed_array) }}

CrashenX avatar Apr 26 '23 01:04 CrashenX

I took a detour to convert that into a string:

JSON="["
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
  dir="$(cut -d'/' -f2 <<<"$file")" # always get the secondary folder
  JSONline="\"$dir\","
  # we don't need to iterate on the same directory over and over, so
  # only include it when it wasn't included
  if [[ "$JSON" != *"$JSONline"* ]]; then
    JSON="$JSON$JSONline"
  fi
done
# Remove last "," and add the closing bracket
if [[ $JSON == *, ]]; then
  JSON="${JSON%?}"
fi
JSON="$JSON]"
echo "folders=$( echo "$JSON" )" >> $GITHUB_OUTPUT
echo $JSON

In the following job(s), if they are going to use metrix strategy, do

strategy:
  matrix:
          folder: ${{ fromJSON(needs.detect-changed-files.outputs.matrix) }}

MemphisMeng avatar Apr 26 '23 01:04 MemphisMeng