argoproj/argo-workflows · error

failed to resolve references: %w

Error message

failed to resolve references: %w

What it means

resolveReferences resolves step inputs in parallel (goroutines reporting to errCh). After wg.Wait(), the first error collected is returned; unless it is ErrRequeue (transient, retried), it is wrapped as 'failed to resolve references'. It is the aggregate wrapper for any per-step input resolution failure.

Source

Thrown at workflow/controller/steps.go:569

	errCh := make(chan error, len(stepGroup)) // contains the error during resolveStepReferences
	var wg sync.WaitGroup
	for i, step := range stepGroup {
		parallelStepNum <- step.Name
		wg.Go(func() {
			if refErr := resolveStepReferences(i, step, newStepGroup); refErr != nil {
				woc.log.WithFields(logging.Fields{"stepName": step.Name}).WithError(refErr).Error(ctx, "Failed to resolve references")
				errCh <- refErr
			}
			<-parallelStepNum
		})
	}
	wg.Wait()

	if err := errorFromChannel(errCh); err != nil { // fetch the first error during resolveStepReferences
		if errors.Is(err, ErrRequeue) {
			return nil, err
		}
		return nil, fmt.Errorf("failed to resolve references: %w", err)
	}
	return newStepGroup, nil
}

// expandStepGroup looks at each step in a collection of parallel steps, and expands all steps using withItems/withParam
func (woc *wfOperationCtx) expandStepGroup(ctx context.Context, sgNodeName string, stepGroup []wfv1.WorkflowStep, stepsCtx *stepsContext) ([]wfv1.WorkflowStep, error) {
	newStepGroup := make([]wfv1.WorkflowStep, 0)
	for _, step := range stepGroup {
		if !step.ShouldExpand() {
			newStepGroup = append(newStepGroup, step)
			continue
		}
		expandedStep, err := woc.expandStep(ctx, step, stepsCtx.scope)
		if err != nil {
			return nil, err
		}
		if len(expandedStep) == 0 {
			// Empty list

View on GitHub (pinned to 35bff19146)

Solutions

  1. Look at the wrapped inner error to find which step/reference failed
  2. Fix the referenced expression or mark inputs optional where appropriate
  3. If it's ErrRequeue-related (transient), the controller will retry automatically — check controller logs if it persists

Example fix

// before
- name: use
  template: consume
  arguments:
    parameters:
      - name: x
        value: '{{steps.build.outputs.parameters.x}}' // build skipped -> unresolved
// after
- name: use
  template: consume
  when: '{{steps.build.status}} == Succeeded'
  arguments:
    parameters:
      - name: x
        value: '{{steps.build.outputs.parameters.x}}'
Defensive patterns

Strategy: validation

Validate before calling

// validate expressions before submit
argo lint my-wf.yaml

Try / catch

if strings.Contains(err.Error(), "failed to resolve references") {
    // inspect wrapped cause to find the offending step/reference
}

Prevention

When it happens

Trigger: Any step in the group fails parameter/artifact reference resolution during expandStepGroup — e.g. unresolved {{steps.*}} expressions, missing outputs — and the error is not an ErrRequeue.

Common situations: Referencing outputs of a skipped or failed step; malformed template expressions; wrong variable names in inputs.parameters.value.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/03b655e59d0e0742. Report an issue: GitHub.