Summary
When a workflow input is declared with required: false but no default value, and the user doesn't provide a value at runtime, any template referencing that input fails with "Unresolved variables" error.
Expected behavior: Optional inputs should resolve to null when not provided, allowing templates to work.
Reproduction
Test case 1: Optional input without default (FAILS)
{
"inputs": {
"optional_name": {
"type": "string",
"required": false
}
},
"nodes": [{
"id": "greet",
"type": "shell",
"params": {
"stdin": {"value": "${optional_name}"},
"command": "jq ."
}
}],
"edges": []
}
$ pflow workflow.json
❌ Workflow execution failed
Error: Unresolved variables in parameter 'stdin': ${optional_name}
Test case 2: Optional input WITH default (WORKS)
Same workflow but with "default": null added:
"optional_name": {
"type": "string",
"required": false,
"default": null
}
$ pflow workflow.json
✓ Workflow completed
{"value": null}
Root Cause
In workflow_validator.py, the prepare_inputs() function handles optional inputs without defaults by doing nothing:
else:
# Optional with no default key means it can be omitted entirely
logger.debug(f"Optional input '{input_name}' not provided and has no default", ...)
# NOTE: Nothing added to defaults dict!
This means the input key is never added to the context, so template resolution fails because variable_exists() returns False.
Secondary Issue: Misleading Error Messages
When a parameter contains multiple template variables and only some fail to resolve, the error message incorrectly lists ALL variables as unresolved:
{
"stdin": {
"has_value": "${provided}",
"no_value": "${missing}"
}
}
$ pflow workflow.json provided=hello
Error: Unresolved variables in parameter 'stdin': ${provided}, ${missing}
Available context keys:
• provided (str): hello
The error says ${provided} is unresolved, but it's clearly in the context! This is confusing for debugging.
Impact
- Workaround tax: Users must add
"default": null to every optional input, even when semantically unnecessary
- Confusing errors: Error messages suggest ALL templates failed when only some did
- Semantic inconsistency: Input validation says "optional inputs can be omitted entirely" but template validation requires them to exist
Proposed Fix
-
In prepare_inputs(), add optional inputs without defaults to the context with value None:
else:
defaults[input_name] = None
-
In _build_enhanced_template_error(), filter to only actually unresolved variables:
variables = {v for v in all_variables if not TemplateResolver.variable_exists(v, context)}
Environment
- pflow version: current main
- Python: 3.13
- OS: macOS
Summary
When a workflow input is declared with
required: falsebut nodefaultvalue, and the user doesn't provide a value at runtime, any template referencing that input fails with "Unresolved variables" error.Expected behavior: Optional inputs should resolve to
nullwhen not provided, allowing templates to work.Reproduction
Test case 1: Optional input without default (FAILS)
{ "inputs": { "optional_name": { "type": "string", "required": false } }, "nodes": [{ "id": "greet", "type": "shell", "params": { "stdin": {"value": "${optional_name}"}, "command": "jq ." } }], "edges": [] }Test case 2: Optional input WITH default (WORKS)
Same workflow but with
"default": nulladded:$ pflow workflow.json ✓ Workflow completed {"value": null}Root Cause
In
workflow_validator.py, theprepare_inputs()function handles optional inputs without defaults by doing nothing:This means the input key is never added to the context, so template resolution fails because
variable_exists()returnsFalse.Secondary Issue: Misleading Error Messages
When a parameter contains multiple template variables and only some fail to resolve, the error message incorrectly lists ALL variables as unresolved:
{ "stdin": { "has_value": "${provided}", "no_value": "${missing}" } }The error says
${provided}is unresolved, but it's clearly in the context! This is confusing for debugging.Impact
"default": nullto every optional input, even when semantically unnecessaryProposed Fix
In
prepare_inputs(), add optional inputs without defaults to the context with valueNone:In
_build_enhanced_template_error(), filter to only actually unresolved variables:Environment