Skip to content

fix!: drop values when skipped arguments are being substituted#16223

Open
isubasinghe wants to merge 1 commit into
argoproj:mainfrom
pipekit:expression-default-handling
Open

fix!: drop values when skipped arguments are being substituted#16223
isubasinghe wants to merge 1 commit into
argoproj:mainfrom
pipekit:expression-default-handling

Conversation

@isubasinghe

@isubasinghe isubasinghe commented Jun 4, 2026

Copy link
Copy Markdown
Member

Motivation

Skipped/omitted node outputs resolved to "", so: producer valueFrom.default was ignored, consumer input defaults were clobbered, and ?? never fired (value was
present-empty, not absent).

Modifications

  • Skipped/omitted outputs are nil in scope (absent optional); simple {{...}} refs still flatten to "" (preserves fix: populate scope with empty values for outputs of skipped/omitted … #15932 no-requeue behavior).
  • Producer valueFrom.default applies; else consumer input default applies (dropSkippedDefaultedArgs); else "".
  • New ReplaceStrictAny preserves nil into expression envs, so ?? works in inline {{=...}} args and when clauses, not just
    valueFrom.expression/fromExpression.
  • Nil expression result with all identifiers present in env collapses to "" instead of staying unresolved.
  • Refactor: unified identifier-vs-env checks on AST-based missingVarsInEnv; removed lexer-token hasVariableInExpression/searchTokens/filterEOF.
  • Behavior change: expressions doing e.g. skippedRef + '-suffix' now see nil (error) instead of ""; use ??.

Verification

New unit tests (TestReplaceStrictAnyNilValues, Test_missingVarsInEnv) and controller tests (TestDAGSkippedOutput*, TestDAGSkippedInlineExpressionFallback,
TestStepsSkippedOutputDefault, examples_skipped_defaults_test.go). Full workflow/controller, workflow/validate, workflow/common, util/template suites pass.

Documentation

New examples in examples/skipped-output-defaults/.

AI

Claude Code was used for code, tests, and this description, under human review.

@isubasinghe isubasinghe marked this pull request as ready for review June 5, 2026 06:51
@isubasinghe isubasinghe requested review from a team as code owners June 5, 2026 06:51
@Joibel Joibel self-assigned this Jun 5, 2026
@Joibel Joibel added cherry-pick/3.7 Cherry-pick this to release-3.7 cherry-pick/4.0 Cherry-pick this to release-4.0 labels Jun 5, 2026

@Joibel Joibel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

docs/variables.md needs updating too for this behaviour (steps L#157 and dag L#176)

docs/enahanced-depends-logic.md should should mention new behaviour too

This is breaking so should get ! in PR title and upgrading.md note

Comment thread workflow/controller/dag_test.go Outdated
Comment thread workflow/controller/scope.go Outdated
// input default for that parameter. Removing the argument lets that input default apply instead of the
// empty skipped placeholder. Arguments whose input has no default are left intact (empty value) so the
// reference still resolves and the node stays live (preserving the #15932 requeue-loop fix).
func (woc *wfOperationCtx) dropSkippedDefaultedArgs(ctx context.Context, tmplCtx *templateresolution.TemplateContext, holder wfv1.TemplateReferenceHolder, origArgs wfv1.Arguments, resolved *wfv1.Arguments, scope *wfScope) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This really feels like it should return err and let callers deal with those failures we're swallowing here otherwise those failures will result in the old bad behaviour

Comment thread workflow/controller/scope.go Outdated
// addSkippedOutputParamToScope registers an output parameter of a skipped/omitted node. If the
// producing template declared a valueFrom.default for the parameter, that default is used as the
// scope value so every consumer (task inputs and template-output aggregation alike) sees it.
// Otherwise it falls back to addSkippedParamToScope's empty-value-plus-marker behavior.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

empty-value-plus-marker is no longer what happens here (just comment is wrong)

Comment thread workflow/controller/dag_test.go
Comment thread util/template/expression_template.go Outdated
@isubasinghe isubasinghe changed the title fix: drop values when skipped arguments are being substituted fix!: drop values when skipped arguments are being substituted Jun 10, 2026
References to output parameters of steps and tasks that were Skipped
(when was false) or Omitted (depends unsatisfied) now resolve instead
of requeuing forever or erroring.

A producer's valueFrom.default applies to every reference. Otherwise
the output is absent: simple tags substitute an empty string, an
argument that is purely such a reference is dropped so the consuming
template's input default applies, and expression tags see nil so
expr-lang `??` fallbacks work. An expression that does not handle the
nil fails the node with a terminal error rather than leaving the
workflow stuck. A legitimately empty output ("") is not absent.

These semantics apply uniformly to step and task arguments, when
clauses, lifecycle hook and exit handler arguments and expressions,
nested template tags, and template output aggregation (where a
valueFrom.default on the aggregating parameter applies when the
reference is absent or the expression fails).

BREAKING CHANGE: expressions referencing a skipped/omitted output that
declared no valueFrom.default see nil instead of "": comparisons such
as `== ''` no longer match, and an expression that does not handle the
nil (e.g. a bare `{{= tasks.x.outputs.parameters.y}}` without `??`)
fails the node instead of resolving.

Documented in docs/variables.md (Outputs of Skipped and Omitted Nodes)
and docs/upgrading.md, with runnable examples under
examples/skipped-output-defaults/.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: isubasinghe <isitha@pipekit.io>
@isubasinghe isubasinghe force-pushed the expression-default-handling branch from 926def7 to c89954f Compare June 10, 2026 04:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cherry-pick/3.7 Cherry-pick this to release-3.7 cherry-pick/4.0 Cherry-pick this to release-4.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants