Skip to content

Renamed workflow identifiers are never rewritten inside {% %} statements or mid-expression Jinja references #7559

Open

Description

@dev-synthia

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-loop Condition, which the docs describe as a Jinja template with the reserved {{ current_index }} counter (docs/cloud/building-agents/configure-blocks.mdx). current_index is at the head; the parameter being compared against never is.
  • Statement references: anything inside {% if ... %} / {% for ... %} is never matched at all, including {label}_output guards 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 #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.

Activity

  1. added 2 commits that reference this issue on Jul 21, 2026
    9cb4927
    09d9ca5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions