Referencing the output of a `Failed` step under `continueOn` requeues forever instead of failing (since #15442); the workflow cannot be ended by its deadline or by `shutdown`
Pre-requisites
- I have double-checked my configuration
- I have tested with the
:latestimage 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?
Since #15442 (v4.0.0, cherry-picked to v3.7.11 in #15657), an unresolved {{steps.X.outputs.parameters.Y}} or {{tasks.X...}} reference in a step returns ErrRequeue and the workflow is requeued. The intent was to wait for a step that has not finished yet. There is no check that the referenced node is already fulfilled, so a reference that can never resolve makes the workflow reconcile every DEFAULT_REQUEUE_TIME (10s) forever.
The skipped/omitted node case has since been covered (#15841, #15932, #16223 populate declared outputs of skipped nodes into scope). A node that finished Failed or Error without producing any outputs is not covered. That happens whenever a pod is killed before its wait container reports a task result: most commonly when activeDeadlineSeconds fires while the pod is Pending or Running. With continueOn on that step the step group is marked successful, the next step's when (or arguments) references the missing output, and the workflow spins.
Consequences, all confirmed with the workflow below on v4.1.2:
- The workflow stays
Runningforever with an unchangedresourceVersion, loggingFailed to resolve references ... error=requeueevery 10s. activeDeadlineSecondscannot end it. After the deadline the controller only refuses to create new pods and fails retries; nothing marks the workflow itself Failed.spec.shutdown: Terminatedoes not end it either. Only deleting the workflow does.- Because it never completes, TTL GC never runs. Each new occurrence is a permanent extra reconcile every 10s.
Before v3.7.11 / v4.0.0 the same situation errored the step group (failed to resolve references) and the workflow failed at the deadline, which was the correct outcome.
Expected: if the referenced node is fulfilled and the variable is still missing, fail the step group (as before #15442) so the workflow completes. Only requeue while the referenced node is not yet fulfilled.
Workaround for template authors: use an expression tag with a fallback, e.g. {{= steps.producer.outputs.parameters.flag ?? 'false' }}, so the tag never fails to resolve. A valueFrom.default on the producer's output does not help here because a pod that never reported a task result has no outputs at all.
Version(s)
v4.1.2 (reproduced), v3.7.17 (seen in the field). The requeue path in workflow/controller/steps.go on main is unchanged, so :latest is affected as well.
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.
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: deadline-requeue-loop-
spec:
entrypoint: main
# Short deadline so the producer step is still Pending when it fires.
activeDeadlineSeconds: 20
templates:
- name: main
steps:
- - name: producer
template: producer
# Tolerate the failure so the step group is still considered successful.
continueOn:
failed: true
error: true
- - name: consumer
template: print
# The status tag always resolves. The output tag never does: a node that was
# killed by the deadline before running has no outputs, not even the default.
when: '{{steps.producer.status}} == Succeeded && "{{steps.producer.outputs.parameters.flag}}" == "true"'
arguments:
parameters:
- name: msg
value: "producer said {{steps.producer.outputs.parameters.flag}}"
- name: producer
retryStrategy:
limit: "2"
outputs:
parameters:
- name: flag
valueFrom:
path: /tmp/flag
default: "false"
# Unschedulable on purpose so the pod is still Pending at the deadline and never
# reports a task result. Any pod killed before its wait container reports behaves the same.
nodeSelector:
does-not-exist: "true"
container:
image: alpine:3.20
command: [sh, -c]
args: ["echo true > /tmp/flag"]
- name: print
inputs:
parameters:
- name: msg
container:
image: alpine:3.20
command: [echo, "{{inputs.parameters.msg}}"]Resulting node tree (workflow stays Running indefinitely):
Steps Running deadline-requeue-loop-chr5k
StepGroup Succeeded [0]
Retry Failed producer retry exceeded workflow deadline 2026-09-15 16:38:13 +0000 UTC (no outputs)
Pod Failed producer(0) Step exceeded its deadline (no outputs)
StepGroup Running [1]Patching spec.shutdown: Terminate afterwards leaves it Running and still looping.
Logs from the workflow controller
kubectl logs -n argo deploy/workflow-controller | grep ${workflow}
time=2026-09-15T16:38:23.669Z level=INFO msg="Processing workflow" namespace=argo component=workflow_worker workflow=deadline-requeue-loop-chr5k phase=Running resourceVersion=586702
time=2026-09-15T16:38:23.669Z level=ERROR msg="Failed to resolve references" stepName=consumer component=workflow_worker workflow=deadline-requeue-loop-chr5k namespace=argo error=requeue
time=2026-09-15T16:38:33.670Z level=INFO msg="Processing workflow" workflow=deadline-requeue-loop-chr5k phase=Running resourceVersion=586702 namespace=argo component=workflow_worker
time=2026-09-15T16:38:33.671Z level=ERROR msg="Failed to resolve references" component=workflow_worker workflow=deadline-requeue-loop-chr5k namespace=argo stepName=consumer error=requeue
time=2026-09-15T16:38:43.672Z level=INFO msg="Processing workflow" workflow=deadline-requeue-loop-chr5k namespace=argo component=workflow_worker phase=Running resourceVersion=586702
time=2026-09-15T16:38:43.673Z level=ERROR msg="Failed to resolve references" error=requeue workflow=deadline-requeue-loop-chr5k namespace=argo stepName=consumer component=workflow_worker
time=2026-09-15T16:38:53.674Z level=INFO msg="Processing workflow" workflow=deadline-requeue-loop-chr5k phase=Running resourceVersion=586702 namespace=argo component=workflow_worker
time=2026-09-15T16:38:53.674Z level=ERROR msg="Failed to resolve references" component=workflow_worker workflow=deadline-requeue-loop-chr5k namespace=argo stepName=consumer error=requeue
... (repeats every 10s, resourceVersion never changes)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
(no output: the producer pod never scheduled, which is the point)Source: argoproj/argo-workflows