Skip to content

fix(ui): show a failed promotion step's own error message - #6857

Open
Marvin9 wants to merge 2 commits into
mainfrom
fix/6851-failed-step-message
Open

fix(ui): show a failed promotion step's own error message#6857
Marvin9 wants to merge 2 commits into
mainfrom
fix/6851-failed-step-message

Conversation

@Marvin9

@Marvin9 Marvin9 commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Closes #6851

The alert under a failed step read promotion.status.message. That message keeps changing as later steps execute, so it flickers; with continueOnError it never reflects the failed step at all; and with multiple failures it showed one step's error under every failed step, leaving the others unreachable. It now reads status.stepExecutionMetadata[i].message.

Working through it, we found the old alert was also serving as the promotion-level message, anchored under the last step -- which is why Errored was excluded from the bottom alert. So repointing the inline alert left that message homeless. It keeps its place after the last step, now shown only when no step surfaced an error of its own.

That last condition is structural rather than a text comparison, following the backend's branches: DetermineFinalPhase copies the worst step's message verbatim (already inline), while abort, pre-step and workdir failures leave the step message empty and so still render. Known gap: a panic or status-patch failure after a step failed is suppressed -- recovering it needs provenance the status doesn't carry, so it belongs backend-side.

Also fixes duplicate React keys when continueOnError lets two steps fail.

Test plan

  • pnpm typecheck, pnpm lint, pnpm vitest run (277 pass) -- all clean
  • Manual: a promotion where step 2 fails and step 3 keeps running -- step 2's alert stays pinned to its own error
  • Manual: abort a running promotion -- "Promotion terminated by ..." still shows after the last step

No unit test: ui/ has vitest only, no jsdom/RTL, and the fix is inline rather than an extracted helper.

🤖 Generated with Claude Code

The alert under a failed step read promotion.status.message, which keeps
changing as later steps execute and, for a continueOnError step, never
reflects that step at all. Read status.stepExecutionMetadata[i].message
instead, so each failed step shows the error that actually caused it.

The promotion-level message keeps its place after the last step, shown
only when no step surfaced an error of its own -- which is how the abort,
pre-step and workdir failures stay visible.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com>
@Marvin9
Marvin9 requested a review from a team as a code owner August 21, 2026 13:13
@netlify

netlify Bot commented Aug 21, 2026

Copy link
Copy Markdown

Deploy Preview for docs-kargo-io ready!

Name Link
🔨 Latest commit 9cc9c0c
🔍 Latest deploy log https://app.netlify.com/projects/docs-kargo-io/deploys/6a8d215afd7c3a000835ff5d
😎 Deploy Preview https://deploy-preview-6857.docs.kargo.io
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@kargo-governance-bot kargo-governance-bot Bot added area/ui Affects the UI kind/bug Something isn't working as intended; If unsure that something IS a bug, start a discussion instead needs/priority Priority has not yet been determined; a good signal that maintainers aren't fully committed labels Aug 21, 2026
@Marvin9 Marvin9 added priority/normal This is the priority for most work and removed needs/priority Priority has not yet been determined; a good signal that maintainers aren't fully committed labels Aug 21, 2026
@Marvin9

Marvin9 commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

This is how UI interprets now:

Each individual step which is terminal + not-succeeded will carry error message and UI will show it below that promotion step. In this case - terminal or non-terminal promotion will carry promotion.status.message as copy of one-of those step's message. UI will not show that promotion.status.message at the end.

When promotion is terminal + not-succeeded and if none of promotion step carries any message, then only promotion.status.message will be shown at the end.

@codecov

codecov Bot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 31.13%. Comparing base (af85cd1) to head (f044bc8).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6857   +/-   ##
=======================================
  Coverage   31.13%   31.13%           
=======================================
  Files         832      832           
  Lines       81235    81235           
=======================================
  Hits        25294    25294           
  Misses      54470    54470           
  Partials     1471     1471           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@hairyhum

Copy link
Copy Markdown
Contributor

The step message is now correct, however when I abort a promotion I no longer see Promotion terminated by admin message. This was previously shown at the bottom after all steps.
The message is in promotion status if I check yaml.

@Marvin9

Marvin9 commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

@hairyhum I tried and it is showing. Maybe be there is some edge case I am missing. Can you share the promotion manifest for the terminated message not showing up?

Screenshot 2026-08-24 at 11 42 32 AM (2)

@hairyhum

Copy link
Copy Markdown
Contributor

I'm running this:

promotionTemplate:
    spec:
      vars:
        - name: gitRepo
          value: https://github.com/hairyhum/steps-test.git
      steps:
        - uses: fail
          as: fail
        - uses: fail
          as: fail-1
          if: ${{ always() }}
          config:
            message: fail 1 is failed
        - uses: set-freight-alias
          as: set-alias
          if: ${{ always() }}
          config:
            alias: smth
            name: 2cda9e9bdcfcd6e402cf5cad4c60fdeedfc045b6
        - uses: compose-output
          as: compose-output
          config:
            commit: ${{ commitFrom(vars.gitRepo).ID }}
        - uses: git-wait-for-pr
          as: git-wait-for-pr
          if: ${{ always() }}
          config:
            prNumber: 14
            repoURL: https://github.com/hairyhum/kargo-demo-gitops

And this is how promotion looks like:

metadata:
  name: test.01m0jd6qfaez71m40jtwhsq78s.2cda9e9
  generateName: promo-
  namespace: kargo-demo
  uid: ae76e61d-48ed-4e00-86ed-a71b3cec3e75
  resourceVersion: "62377"
  generation: 1
  creationTimestamp: 2026-08-21T14:57:07Z
  labels:
    kargo.akuity.io/stage: test
  annotations:
    kargo.akuity.io/abort: '{"action":"terminate","actor":"admin","controlPlane":true}'
    kargo.akuity.io/create-actor: admin
    kargo.akuity.io/stage: test
  ownerReferences:
    - apiVersion: kargo.akuity.io/v1alpha1
      kind: Stage
      name: test
      uid: ebcc41ba-479c-4861-acd4-86ce4b011d97
      controller: true
      blockOwnerDeletion: true
spec:
  stage: test
  freight: 2cda9e9bdcfcd6e402cf5cad4c60fdeedfc045b6
  vars:
    - name: gitRepo
      value: https://github.com/hairyhum/steps-test.git
  steps:
    - uses: fail
      as: fail
    - uses: fail
      as: fail-1
      if: ${{ always() }}
      config:
        message: fail 1 is failed
    - uses: set-freight-alias
      as: set-alias
      if: ${{ always() }}
      config:
        alias: smth
        name: 2cda9e9bdcfcd6e402cf5cad4c60fdeedfc045b6
    - uses: compose-output
      as: compose-output
      config:
        commit: ${{ commitFrom(vars.gitRepo).ID }}
    - uses: git-wait-for-pr
      as: git-wait-for-pr
      if: ${{ always() }}
      config:
        prNumber: 14
        repoURL: https://github.com/hairyhum/kargo-demo-gitops
status:
  phase: Aborted
  message: Promotion terminated by admin
  freight:
    name: 2cda9e9bdcfcd6e402cf5cad4c60fdeedfc045b6
    origin:
      kind: Warehouse
      name: images
    commits:
      - repoURL: https://github.com/hairyhum/steps-test.git
        id: 866d4b7518c64e0dbfc68e65e1fd58c688c29c64
        branch: test
        message: foo
        author: Daniil Fedotov <daniil.fedotov@akuity.io>
        committer: Daniil Fedotov <daniil.fedotov@akuity.io>
  freightCollection:
    id: 94c4af21c07058a8c41d805a0b78227fb994036e
    items:
      Warehouse/images:
        name: 2cda9e9bdcfcd6e402cf5cad4c60fdeedfc045b6
        origin:
          kind: Warehouse
          name: images
        commits:
          - repoURL: https://github.com/hairyhum/steps-test.git
            id: 866d4b7518c64e0dbfc68e65e1fd58c688c29c64
            branch: test
            message: foo
            author: Daniil Fedotov <daniil.fedotov@akuity.io>
            committer: Daniil Fedotov <daniil.fedotov@akuity.io>
  startedAt: 2026-08-21T14:57:07Z
  finishedAt: 2026-08-21T14:57:19Z
  currentStep: 4
  stepExecutionMetadata:
    - alias: fail
      startedAt: 2026-08-21T14:57:07Z
      finishedAt: 2026-08-21T14:57:07Z
      status: Failed
      message: 'step "fail": failed'
    - alias: fail-1
      startedAt: 2026-08-21T14:57:07Z
      finishedAt: 2026-08-21T14:57:07Z
      status: Failed
      message: 'step "fail-1": failed: fail 1 is failed'
    - alias: set-alias
      startedAt: 2026-08-21T14:57:07Z
      finishedAt: 2026-08-21T14:57:07Z
      status: Succeeded
      message: updated alias of Freight "2cda9e9bdcfcd6e402cf5cad4c60fdeedfc045b6"
        from "smth" to "smth"
    - alias: compose-output
      status: Skipped
    - alias: git-wait-for-pr
      startedAt: 2026-08-21T14:57:07Z
      finishedAt: 2026-08-21T14:57:19Z
      status: Aborted
  state:
    git-wait-for-pr:
      commit: a4f418fa87aca5efa37f0c1a4bd5a2677dfe91f0
      pr:
        id: 14
        merged: false
        open: true
        url: https://github.com/hairyhum/kargo-demo-gitops/pull/14

This is how it looks like in main:
Screenshot 2026-08-24 at 11 04 54 AM

This is how it looks like in this branch:
Screenshot 2026-08-24 at 11 08 34 AM

@Marvin9

Marvin9 commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Oh okay now I know the reason @hairyhum

We still need to show promotion.status.message if phase is Aborted

Split the promotion-level message visibility check into per-phase cases.
Failed and Errored keep suppressing the message when the failing step
already displays it, but an abort is not attributable to any one step,
so its message is always shown.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com>
@Marvin9

Marvin9 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

@rpelczar @hairyhum please take a look again

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

Labels

area/ui Affects the UI kind/bug Something isn't working as intended; If unsure that something IS a bug, start a discussion instead priority/normal This is the priority for most work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(ui): failed promotion step shows promotion status message instead of its own

2 participants