Skip to content

Validation rejects {{ $item }} as a syntax error; the runtime rewrites it #474

Description

@jeremymanning

The runtime accepts {{ $item }}; validation calls it a syntax error

UnifiedTemplateResolver._preprocess_dollar_variables (unified_template_resolver.py:545) rewrites {{ $variable }} to {{ variable }} before rendering, because "Jinja2 doesn't support variables starting with $". It does the same inside {% %} blocks.

TemplateValidator._validate_syntax parses the raw text, so it reports:

syntax_error

for a template the runtime handles correctly.

Reproduction

TemplateValidator().validate_pipeline_templates(
    {"id": "p", "steps": [{"id": "s", "for_each": "{{ rows }}",
                           "parameters": {"t": "{{ $item }}"}}]},
    {"rows": [1]},
)
# -> is_valid=False, ['syntax_error']

Scope

32 uses across the catalogue — $item (18), $iteration (10), $index (2), $is_first (2) — in files including:

  • examples/control_flow_for_loop.yaml
  • examples/iterative_fact_checker.yaml
  • examples/control_flow_advanced.yaml
  • examples/enhanced_until_conditions_demo.yaml
  • examples/original_research_report_pipeline.yaml

All of these currently fail validation, and this is at least one of the reasons.

Same class as #465, #469 and #472

The compiler/runtime accepts a spelling the validator does not. Each time, the validator's private notion of the language disagreed with the runtime's:

issue disagreement
#465 inferred dependencies rejected rather than used
#469 bare loop names unknown to the template validator
#472 one binding set for every loop construct; source validated in loop scope
this $-prefixed spelling rejected as a syntax error

Fix

Validation should apply the same preprocessing the runtime applies, from a shared implementation rather than a second regex — a reimplementation would be the fourth mechanism problem #466 removed for dependencies.

Once {{ $item }} is normalised to {{ item }} before parsing, the DOLLAR_LOOP_VARIABLES raw-text scan in _validate_variables becomes redundant: the names appear in the AST like any other. That scan exists only because $item cannot be parsed.

Tests

  • {{ $item }} inside a for_each validates and renders to the item
  • {{ $item }} outside a loop is still rejected, as {{ item }} is
  • $-names in {% if %} / {% for %} blocks are handled
  • the preprocessing has one implementation, asserted by identity
  • a pipeline using $item compiles and runs, producing the expected artifact
  • the affected catalogue examples move into the validating baseline

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions