Renamed workflow identifiers are never rewritten inside {% %} statements or mid-expression Jinja references
What happened
replace_jinja_reference in skyvern/utils/templating.py only matches an identifier immediately after {{:
pattern = rf"\{{\{{(\s*){escaped_old_key}(?![a-zA-Z0-9_])"So when the workflow import sanitizer (sanitize_workflow_yaml_with_references, runs on POST /workflows and POST /workflows/{id} with a yaml_definition) renames a parameter key or block label, references are only repaired when they sit at the head of a {{ ... }} expression. Two documented usage shapes are silently skipped:
- Mid-expression references:
{{ current_index < max attempts }}— the exact shape of a while-loopCondition, which the docs describe as a Jinja template with the reserved{{ current_index }}counter (docs/cloud/building-agents/configure-blocks.mdx).current_indexis at the head; the parameter being compared against never is. - Statement references: anything inside
{% if ... %}/{% for ... %}is never matched at all, including{label}_outputguards like{% if my-block_output.success %}.
Impact
After a rename (invalid identifier or a collision-driven _2 suffix), the skipped references keep pointing at the old name. With default lax templating nothing errors at import or run time — conditions evaluate against undefined/wrong values, so loops mis-terminate and guards mis-fire. When the rename was collision-driven, the stale reference can silently bind to the other parameter that now owns the old name.
Reproduce
from skyvern.utils.templating import replace_jinja_reference
replace_jinja_reference("{{ current_index < max_attempts }}", "max_attempts", "max_attempts_2")
# returns unchanged; expected "{{ current_index < max_attempts_2 }}"
replace_jinja_reference("{% if my_flag %}go{% endif %}", "my_flag", "my_flag_2")
# returns unchanged; expected "{% if my_flag_2 %}go{% endif %}"The same matcher backs every rewrite path in the sanitizer, including the sentinel-guarded _rewrite_error_code_mapping_refs_atomic, so all of them share the coverage gap.
Notes
This is the matching-coverage defect noted at the end of Skyvern-AI/skyvern#7554 (scoped out of #7555, which fixes the separate chaining problem). PR incoming that widens the matcher to full-token occurrences inside {{ ... }} and {% ... %} spans while leaving prose outside Jinja delimiters, attribute accesses, quoted string literals, and longer identifiers untouched.
Source: Skyvern-AI/skyvern