Skip to content

Conversation

@ajaykn
Copy link
Contributor

@ajaykn ajaykn commented Mar 9, 2023

Please note that this is not supported yet, and Server side changes are still in-progess

we will release a changelog when supported end to end.

Currently outputs for matrix jobs are represented by a single output and only the last successful matrix job is used to populate the output. This prevents users from being able to target output from a specific job and can lead to unpredictable results since the matrix jobs don't run in a guaranteed order.

So as part of the improvements, we want to support
Allow the matrix context to be used to define the output variable name. This allows users to make the output completely deterministic if they choose to include all dimensions of the matrix in their key.

outputs:
  ${{ matrix.os }}_${{ matrix.arch }}_result: ${{ steps.step1.outputs.test }}

Example using all dimensions in output key:

jobs:
  job1:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        os: ['linux', 'windows','macos']
        arch: ['x86','x64']
    outputs:
      ${{ matrix.os }}_${{ matrix.arch }}_result: ${{ steps.step1.outputs.test }}
    steps:
      - id: step1
        run: "test=${{ matrix.os }} - ${{ matrix.arch }}" >> $GITHUB_OUTPUT
  job2:
    runs-on: ubuntu-latest
    needs: job1
    steps:
      - run: echo ${{ needs.job1.outputs["linux_x86_result"] }}

Please note that: Server side changes are still in-progess.

@ajaykn ajaykn requested a review from a team as a code owner March 9, 2023 02:31
@0x53A
Copy link

0x53A commented Mar 13, 2023

hallelujah, this is great news! Thank you.

Please note that: Server side changes are still in-progess

is there a public issue we can watch?

@srosell-ut
Copy link

srosell-ut commented Mar 14, 2023

Hey @ajaykn 🖖 !
this is just what we were looking for but although it seems to be merged and deployed in the release v2.303.0 it seems to not work as the example shows. We've tried and we get the following error:

image

The workflow is not valid. .github/workflows/test.yaml (Line: 16, Col: 7): Unrecognized named-value: 'matrix'. Located at position 1 within expression: matrix.os .github/workflows/test.yaml (Line: 24, Col: 14): Unexpected symbol: '"linux_x86_result"'. Located at position 20 within expression: needs.job1.outputs["linux_x86_result"]

We just copy/paste you example as it was not working in our use case to see if we where doing something wrong but we have the same error.

Are we missing something? 🤔 I guess it is still something missing due to the side-note:

Please note that: Server side changes are still in-progess

Thanks for the work 🙇

@SvenStaehs
Copy link

SvenStaehs commented Mar 15, 2023

Love it, just started getting stuck on this issue. To my untrained eye, the changes look like they only affect job outputs, not workflow outputs (for reusable workflows where the workflows are called with a matrix), is that a separate change? Because trying the same syntax on those gives me Unexpected symbol: '"build-image-${{' trying to dereference in the workflow that needs this as an input.

Edit: I re-checked the example and noticed it uses a hard-coded string to resolve the output, not something like echo ${{ needs.job1.outputs["${{ matrix.os }}_${{ matrix.arch }}_result"] }}, which is what I need: My job2 runs on the same matrix as job1 and the respective second jobs are supposed to use the outputs of the respective first jobs that ran for the same matrix values... So maybe this implementation doesn't really cover my specific use-case completely?

@griseau
Copy link

griseau commented Mar 15, 2023

Such a great improvement ! Do you have any ETA for this ? So that I know if I need to make a workaround or can just wait !
Thanks a lot

@caio-eiq
Copy link

caio-eiq commented Mar 22, 2023

@ajaykn is this already working on v2.303.0?
I am running into a similar error as mentioned by @srosell-uz

@ajaykn
Copy link
Contributor Author

ajaykn commented Mar 23, 2023

@srosell-uz , @caio-eiq

Please note that there are still few more changes from server side.
We will release a changelog / blog post once we support end to end.

@griseau
Currently under internal testing and will be released in another 2-3 weeks.

@SvenStaehs

To my untrained eye, the changes look like they only affect job outputs, not workflow outputs (for reusable workflows where the workflows are called with a matrix), is that a separate change?

We wil share more in blog post once the feature is completely baked.
To give you initial idea, for reusable wf outputs, we were thinking to support via inputs context.

caller workflow
job1:
    strategy:
      matrix:
        os: ['linux', 'windows','macos']
        arch: ['x86','x64']
    uses: ./.github/workflows/called1.yml
    with:
      os: ${{ matrix.os }}
      arch: ${{ matrix.arch }} 
job2:
    runs-on: ubuntu-latest
    needs: job1
    steps:
      - run: echo ${{ needs.job1.outputs["linux_x86_result"] }}
called workflow
on:
  workflow_call:
    inputs:
      os:
        type: string
      arch:
        type: string
    outputs:
      ${{ inputs.os }}_${{ inputs.arch }}_result:
        value: ${{ jobs.job1.outputs.result}}

Edit: I re-checked the example and noticed it uses a hard-coded string to resolve the output, not something like echo ${{ needs.job1.outputs["${{ matrix.os }}_${{ matrix.arch }}_result"] }}, which is what I need: My job2 runs on the same matrix as job1 and the respective second jobs are supposed to use the outputs of the respective first jobs that ran for the same matrix values... So maybe this implementation doesn't really cover my specific use-case completely?

yes currently, we will not be supporting expressions inside an expression like ${{ needs.job1.outputs["${{ matrix.os }}_${{ matrix.arch }}_result"] }}

@ajaykn ajaykn changed the title Support matrix context in output keys Preparation work for Supporting matrix context in output keys Mar 23, 2023
@ChristopherHX
Copy link
Contributor

expressions inside an expression is not required to access composed output keys.

${{ needs.job1.outputs["${{ matrix.os }}_${{ matrix.arch }}_result"] }}

This can be rewritten to ${{ needs.job1.outputs[format('{0}_{1}_result', matrix.os, matrix.arch)] }}, only downside is that syntax is harder to write (and read) for workflow authors.

@brianjmurrell
Copy link

Could we get an update when the server-side bits have been completed and are live so that the change described here can work please?

(Note I am not asking for an ETA, just a note here when it's complete so that we know we can start using this change.)

@nicholasbergesen
Copy link
Contributor

Hi all, unfortunately the team working on this feature has been laid off. I have no information on whether or not the work will be continued by another team or if the work has stopped completely. Its quite sad as it was very close to completion.

cc @mph4

@brianjmurrell
Copy link

This is a real pity as this is a pretty serious feature gap. Not being able to get matrix per intersection outputs seriously impacts the usability of the matrix feature.

@qc00
Copy link

qc00 commented Apr 14, 2023

There's no design documentation linked, so I am not sure what alternative syntax was considered, but templating in the field name seems to be a bit limiting because the user of the outputs will then have to enumerate all the needed field names somehow.

This will either lead to a hard-coded, manual expansion of the matrix combinations, or some convoluted code to reuse the matrix definition.

Why not allow nested objects so we can use the existing [object filter] feature?

For example:

outputs:
  my_output:
    key: ${{matrix.os}}
    nested:
      key: ${{matrix.arch}}
      value: ...

# Usage:
${{jobs.x.outputs.my_output.*.*}}
${{jobs.x.outputs.my_output.linux.*}}
${{jobs.x.outputs.my_output.*.x64}}

The last two use cases are almost impossible with the current syntax

@MatthiasValvekens
Copy link

This will either lead to a hard-coded, manual expansion of the matrix combinations, or some convoluted code to reuse the matrix definition.

Wouldn't that be solvable with strategy.job-index as a unique identifier?

nikola-jokic pushed a commit to nikola-jokic/runner that referenced this pull request May 12, 2023
@andrewstec
Copy link

Can we please get an update on this? I understand the layoffs have occurred. Is there a PM/team who still has this in the product roadmap or is this indefinitely scrapped?

@RafPe
Copy link

RafPe commented May 30, 2023

Having this feature would make dynamic CICD with github actions a 💥 If there is any help we as community could contribute please let us know!

@patrickmoore-nc
Copy link

Just investigated parameterising a few similar jobs using matrix and I am in total disbelief this functionality wasn't provided from the get-go. It's something that every user of the matrix feature would obviously want.

@Zermond
Copy link

Zermond commented Jul 26, 2023

Does it work in cloud runner? Because I got error just like srosell-ut

@RafPe
Copy link

RafPe commented Jul 27, 2023

It will not work until Github pushes backend changes to support this 😢

@mrclrchtr
Copy link

Is this still not solved?

@maximveksler
Copy link

github, yet another ping on this.

@ceguimaraes
Copy link

Any updates?

@wernc23
Copy link

wernc23 commented Oct 25, 2024

Still looking for a resolution on this.

@elviskahoro
Copy link

I brought this up to multiple people from GitHub at GitHub Universe (a YEAR ago). And here we are...

Still looking for a resolution on this.

@nicholasbergesen
Copy link
Contributor

Hey folks, I was leading this feature before layoffs happened at GitHub, its quite painful to see the activity on here, which I keep getting notifications for every time someone comments. While I'm no longer employed at GitHub I'm going to reach out to some folks and see if I can find someone willing to finish up this work.

P.S. Don't let this get your hopes up too much. 💔

@OscarVanL
Copy link

I'd just like to add that this nondeterministic behaviour isn't merely a feature request, this is a massive footgun in GitHub actions. The silently nondeterministic outputs are dangerous, especially for people that depend on GitHub Actions for reliable builds and production deploys.

I had a look at some of the PRs referencing this issue, take this one, where this bug led to the incorrect helmchart being applied during a kubernetes apply 😱.

If it is too much to ask that this feature is finished, I think it should at least raise a warning when you access a matrix job's output. This would be a good candidate for a GitHub Actions linter.

@rwader-swi
Copy link

its a pity that people working on such most requested feature has been laid off

@ridasaleemsage
Copy link

any updates on this?

@alexmamrenko
Copy link

any news?

@ericsciple
Copy link
Collaborator

Job outputs enable passing information into downstream job-level inputs.

Artifacts generally work well for downstream step-level processing.

Example solution using artifacts
jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        runs-on:
          - ubuntu-latest
          - windows-latest
    steps:
      - run: echo "${{ matrix.runs-on }}_RESULT=success" > "report-${{ matrix.runs-on }}.txt"
      - uses: actions/upload-artifact@v4
        with:
          name: report-${{ matrix.runs-on }}
          path: report-${{ matrix.runs-on }}.txt
  test:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v4
        with:
          pattern: report-*
          merge-multiple: true
      - run: cat report-*

Can someone help me understand their concrete scenario where using artifacts doesn't work?

@brianjmurrell
Copy link

Job outputs enable passing information into downstream job-level inputs.

Artifacts generally work well for downstream step-level processing.

This has been suggested before in previous comments on this issue. It's a hacky work-around at best. It pollutes the end-user visible artifacts with build-related data.

Can someone help me understand their concrete scenario where using artifacts doesn't work?

Needing this is a while ago for me (and my previous job, so I don't really have any skin in this game any more) so I don't recall the details, but IIRC it fell down with dynamically determined matrix axes.

@SvenStaehs
Copy link

yeah, artifacts has been mentioned and a similar example given here: #2477 (comment)
The comment after that one explains how I feel about it ;) "hacky work-around at best" and "pollutes the end-user visible artifacts" is a good summary actually.

@blozano-tt
Copy link

please help

@james-whitaker-arm
Copy link

Another request for this feature. I'm running all jobs in a workflow as a matrix, so that the jobs run in parallel on 6 different operating systems. Currently working around this by using a job output per OS, so 6 job outputs. It's a bit messy.

@praxder
Copy link

praxder commented May 6, 2025

This feature would really make the matrix feature more usable.

@ismael-elatifi
Copy link

ismael-elatifi commented Jun 2, 2025

My workaround is to upload a unique artifact for each matrix job and then I download all artifacts with a pattern :

name: my_workflow
on: pull_request
jobs:
  matrix_jobs:
    runs-on: my_image
    strategy:
      matrix:
        my_var: [1, 2, 3]
    steps:
      - name: Save data to file
        run: echo "some content ${{ matrix.my_var }}" > artifact_${{ github.run_id }}_${{ matrix.my_var }}.txt

      - name: Upload file
        uses: actions/upload-artifact@v4
        with:
          name: artifact_${{ github.run_id }}_${{ matrix.my_var }}
          path: artifact_${{ github.run_id }}_${{ matrix.my_var }}.txt
          retention-days: 1 # Keep artifact for 1 day to save storage
          if-no-files-found: error # Ensure the file was created

  do-something-with-artifacts:
    runs-on: my_image
    needs: matrix_jobs
    steps:
      - name: Download artifacts of matrix jobs
        uses: actions/download-artifact@v4
        with:
          pattern: artifact_${{ github.run_id }}_*
          path: ./output # directory to download artifacts into
          merge-multiple: true  # downloaded artifacts will be in the same directory specified by path

      - run: ls ./output
      # shows : artifact_<run_id>_1.txt  artifact_<run_id>_2.txt  artifact_<run_id>_3.txt

@trinitronx
Copy link

its a pity that people working on such most requested feature has been laid off

☝️💯

“Most managers are incompetent and maintain their jobs via inertia and politics.”

Antonio García Martínez (Chaos Monkeys: Obscene Fortune and Random Failure in Silicon Valley)

@RafPe
Copy link

RafPe commented Sep 18, 2025

its a pity that people working on such most requested feature has been laid off

☝️💯

“Most managers are incompetent and maintain their jobs via inertia and politics.”
Antonio García Martínez (Chaos Monkeys: Obscene Fortune and Random Failure in Silicon Valley)

Sadly its true .... This feature would make Github actions such a epic system!

If any1 from Github is reading this .... Get me on board and I promise I will only work on delivering this feature 🤣

@leighmcculloch
Copy link

The artifact workaround works for some cases, but not all. Specifically, if the output is going to be used in a subsequent job's if, then artifacts don't work at all.

@sigprof
Copy link

sigprof commented Oct 1, 2025

Specifically, if the output is going to be used in a subsequent job's if, then artifacts don't work at all.

Artifacts should work if you add an intermediate job which would download the artifacts, process them and return the results as normal job outputs; then another job could use the values of those outputs.

@brianjmurrell
Copy link

Artifacts should work if you add an intermediate job which would download the artifacts, process them and return the results as normal job outputs; then another job could use the values of those outputs.

How big and complicated (and fragile!) do these Rube Goldberg machines have to get before this issue gets resolved?

@shapirus
Copy link

shapirus commented Oct 2, 2025

Specifically, if the output is going to be used in a subsequent job's if, then artifacts don't work at all.

Artifacts should work if you add an intermediate job which would download the artifacts, process them and return the results as normal job outputs; then another job could use the values of those outputs.

that's what we do.
it sucks to be having to do it like this.

Copy link

@mrwutthisan1990-glitch mrwutthisan1990-glitch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uploading IMG_20251111_030505.jpg…

@mrwutthisan1990-glitch
Copy link

Please note that this is not supported yet, and Server side changes are still in-progess

we will release a changelog when supported end to end.

Currently outputs for matrix jobs are represented by a single output and only the last successful matrix job is used to populate the output. This prevents users from being able to target output from a specific job and can lead to unpredictable results since the matrix jobs don't run in a guaranteed order.

So as part of the improvements, we want to support Allow the matrix context to be used to define the output variable name. This allows users to make the output completely deterministic if they choose to include all dimensions of the matrix in their key.

outputs:
  ${{ matrix.os }}_${{ matrix.arch }}_result: ${{ steps.step1.outputs.test }}

Example using all dimensions in output key:

jobs:
  job1:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        os: ['linux', 'windows','macos']
        arch: ['x86','x64']
    outputs:
      ${{ matrix.os }}_${{ matrix.arch }}_result: ${{ steps.step1.outputs.test }}
    steps:
      - id: step1
        run: "test=${{ matrix.os }} - ${{ matrix.arch }}" >> $GITHUB_OUTPUT
  job2:
    runs-on: ubuntu-latest
    needs: job1
    steps:
      - run: echo ${{ needs.job1.outputs["linux_x86_result"] }}

Please note that: Server side changes are still in-progess.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.