argoproj/argo-workflows · error
output parameters must have a valueFrom specified
Error message
output parameters must have a valueFrom specified
What it means
When the controller resolves a step/DAG template's output parameters from the execution scope (workflow/controller/operator.go:3463), every output parameter must declare how its value is produced via `valueFrom` (parameter, path, expression, default, etc.). A parameter with a `name` but no `valueFrom` has no way to be evaluated, so template resolution fails immediately and the node is marked errored. This check runs before the template's containers even start, catching invalid specs at execution time (full validation also happens at submit via workflow/validate).
Source
Thrown at workflow/controller/operator.go:3463
}
outbound := make([]string, 0)
for _, outboundNodeID := range node.OutboundNodes {
outbound = append(outbound, woc.getOutboundNodes(ctx, outboundNodeID)...)
}
return outbound
}
// getTemplateOutputsFromScope resolves a template's outputs from the scope of the template
func (woc *wfOperationCtx) getTemplateOutputsFromScope(ctx context.Context, tmpl *wfv1.Template, scope *wfScope) (*wfv1.Outputs, error) {
if !tmpl.Outputs.HasOutputs() {
return nil, nil
}
var outputs wfv1.Outputs
if len(tmpl.Outputs.Parameters) > 0 {
outputs.Parameters = make([]wfv1.Parameter, 0)
for _, param := range tmpl.Outputs.Parameters {
if param.ValueFrom == nil {
return nil, fmt.Errorf("output parameters must have a valueFrom specified")
}
val, skipped, err := scope.resolveParameter(param.ValueFrom)
if err != nil {
// We have a default value to use instead of returning an error
if param.ValueFrom.Default == nil {
return nil, err
}
val = param.ValueFrom.Default.String()
} else if skipped && param.ValueFrom.Default != nil {
// The referenced step was skipped/omitted and produced no output; use the declared default.
val = param.ValueFrom.Default.String()
}
if val == nil {
// Skipped/omitted output with no default anywhere — neither the producer's
// valueFrom.default nor this aggregating parameter's own — is an unhandled absent
// 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)
}View on GitHub (pinned to 35bff19146)
Solutions
- Add a `valueFrom` to each output parameter, e.g. `valueFrom: {path: /tmp/result.txt}` or `valueFrom: {parameter: '{{steps.build.outputs.parameters.result}}'}`
- Lint the workflow before submitting (`argo lint file.yaml`) — the validator reports missing valueFrom before execution
- Verify YAML indentation so `valueFrom` is a child of the parameter, not of `outputs.parameters`
- If the value is constant, use `valueFrom: {default: myvalue}` instead of a bare value
Example fix
# before
outputs:
parameters:
- name: result
value: /tmp/out.txt
# after
outputs:
parameters:
- name: result
valueFrom:
path: /tmp/out.txt Defensive patterns
Strategy: validation
Validate before calling
# lint before submit — catches missing valueFrom
# $ argo lint my-workflow.yaml
# programmatic check:
for _, p := range tmpl.Outputs.Parameters {
if p.ValueFrom == nil {
return fmt.Errorf("output parameter %q must specify valueFrom", p.Name)
}
} Type guard
func hasValueFrom(p wfv1.Parameter) bool {
return p.ValueFrom != nil &&
(p.ValueFrom.Path != "" || p.ValueFrom.Parameter != "" ||
p.ValueFrom.Expression != "" || p.ValueFrom.JQFilter != "" ||
p.ValueFrom.JSONPath != "" || p.ValueFrom.Default != nil)
} Try / catch
null
Prevention
- Run `argo lint` on all manifests before submit
- Keep valueFrom correctly indented as a child of the parameter entry
- Use `valueFrom.default` for constant values rather than a bare `value`
- Copy from a known-good output-parameter example rather than writing YAML from scratch
When it happens
Trigger: A workflow spec defines `outputs.parameters` entries lacking `valueFrom` — e.g. hand-written YAML where the valueFrom block was omitted or mis-indented so it parsed as a sibling key; or a template generated programmatically (SDK/JSON) that only sets name/value.
Common situations: Copy-pasting a parameter output example and deleting the valueFrom block; YAML indentation mistakes nesting valueFrom under the wrong key; building specs with the Python/Java SDK and forgetting ValueFrom; upgrading from very old Argo versions where some valueFrom variants were optional.
Related errors
- CodeBadRequest
- unable to parse node field selector '%s': %w
- successCondition, failureCondition and outputs are not suppo
- containers must have at least one container
- malformed workflow template parameter "%s": valueFrom is nil
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/f88310962f4769eb.
Report an issue: GitHub.