argoproj/argo-workflows · error
unable to resolve outputs from scope: %w
Error message
unable to resolve outputs from scope: %w
What it means
After resolving output parameters, the controller resolves each of the template's output artifacts from the scope (workflow/controller/operator.go:3497). If artifact resolution fails for reasons other than the handled 'not found + optional' case, the error is wrapped with 'unable to resolve outputs from scope: %w' and template execution fails. The wrapped inner error (e.g. 'Unable to resolve: {{...}} expression' or an invalid artifact path) is the real cause.
Source
Thrown at workflow/controller/operator.go:3497
// optional: fail terminally, mirroring simple-tag substitution semantics.
return nil, argoerrors.Errorf(argoerrors.CodeBadRequest, "output parameter %q: %q is an absent optional (skipped/omitted node output with no default)", param.Name, param.ValueFrom.Parameter)
}
param.Value = wfv1.AnyStringPtr(val)
param.ValueFrom = nil
outputs.Parameters = append(outputs.Parameters, param)
}
}
if len(tmpl.Outputs.Artifacts) > 0 {
outputs.Artifacts = make([]wfv1.Artifact, 0)
for _, art := range tmpl.Outputs.Artifacts {
resolvedArt, err := scope.resolveArtifact(ctx, &art)
if err != nil {
// If the artifact was not found and is optional, don't mark an error
if strings.Contains(err.Error(), "Unable to resolve") && art.Optional {
woc.log.WithField("artifactName", art.Name).Warn(ctx, "Optional artifact was not found; it won't be available as an output")
continue
}
return nil, fmt.Errorf("unable to resolve outputs from scope: %w", err)
}
if resolvedArt == nil {
continue
}
resolvedArt.Name = art.Name
outputs.Artifacts = append(outputs.Artifacts, *resolvedArt)
}
}
return &outputs, nil
}
func generateOutputResultRegex(name string, parentTmpl *wfv1.Template) (string, string) {
referenceRegex := fmt.Sprintf(`\.%s\.outputs\.result`, name)
expressionRegex := fmt.Sprintf(`\[['\"]%s['\"]\]\.outputs.result`, name)
if parentTmpl.DAG != nil {
referenceRegex = "tasks" + referenceRegex
expressionRegex = "tasks" + expressionRegex
} else if parentTmpl.Steps != nil {View on GitHub (pinned to 35bff19146)
Solutions
- Read the wrapped cause after '%w' — fix the referenced artifact/step name so it exists in scope (names are case-sensitive)
- Mark the artifact `optional: true` only when a missing artifact is acceptable — note the lenient path requires the error to contain 'Unable to resolve'
- Verify the upstream step actually succeeded and produced the artifact (check node status and pod logs)
- For subPath outputs, confirm the subdirectory exists at runtime or add a fallback in the container script
- Use `argo lint` and check DAG/task naming to catch broken references before submission
Example fix
# before
outputs:
artifacts:
- name: model
from: '{{steps.train.outputs.artifacts.modle}}' # typo
# after
outputs:
artifacts:
- name: model
from: '{{steps.train.outputs.artifacts.model}}' Defensive patterns
Strategy: validation
Validate before calling
# verify every artifact reference resolves to an existing step/task name
# argo lint workflow.yaml
# and mark artifacts that may legitimately be absent:
# outputs:
# artifacts:
# - name: report
# optional: true
# from: '{{steps.gen.outputs.artifacts.report}}' Type guard
func artifactRefExists(ref string, scope map[string]any) bool {
_, ok := scope[strings.Trim(ref, "{}")]
return ok
} Try / catch
null
Prevention
- Spell-check `from:` references against actual step/task and artifact names (case-sensitive)
- Use `optional: true` for artifacts that may not be produced
- Check upstream nodes succeeded before relying on their artifacts
- Ensure the container actually writes files to declared output paths
- Run `argo lint` in CI for every workflow manifest
When it happens
Trigger: An output artifact references something absent from the scope: `from:` pointing at a step/task/artifact name that doesn't exist or is misspelled; `subPath:` on an artifact whose subdirectory doesn't exist; a `fromExpression:` that evaluates to nothing; non-optional artifact whose source didn't produce the file.
Common situations: Typos in `from: '{{steps.x.outputs.artifacts.y}}'` references; a task failed/skipped earlier so its artifact never existed; marking an artifact optional doesn't help when the error is something other than 'Unable to resolve' (e.g. malformed expression); container didn't write the declared output path.
Related errors
- single branch mode without a branch specified
- duplicate synchronization item found
- CodeBadRequest
- resolve UID: %w
- resolve UID: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/c562c4215d4d1d23.
Report an issue: GitHub.