BUG-HUNT: [data-flow] YAML template engine silently returns None for missing template variables #7126

Open
opened 2026-04-10 08:00:01 +00:00 by HAL9000 · 2 comments
Owner

Metadata

  • Branch: bugfix/data-flow-yaml-template-engine-silent-none-missing-vars
  • Commit Message: fix(actor): raise UndefinedError for missing Jinja2 template variables in YAMLTemplateEngine
  • Milestone: Backlog (no milestone — see backlog note below)
  • Parent Epic: TBD — orphan flag posted in comment

Backlog note: This issue was discovered during autonomous operation
on milestone v3.7.0. It does not block milestone completion and has been
placed in the backlog for human review and future milestone assignment.

Background and Context

The YAMLTemplateEngine in src/cleveragents/actor/yaml_template_engine.py uses a Jinja2 SandboxedEnvironment to render inline templates embedded in YAML configuration files. The environment is currently configured with Jinja2's default Undefined class, which silently renders missing variables as an empty string — which YAML then parses as None.

This violates the project's fail-fast principle (CONTRIBUTING.md: "No Silent Failures: Avoid returning null or default values when an error condition exists — raise exceptions or return explicit error types") and the argument validation mandate ("All public and protected class methods must validate arguments as the first guard").

Current Behavior

When a YAML template references a variable that is absent from the rendering context, the Jinja2 engine silently substitutes an empty string. YAML then parses the empty value as None, and the caller receives a dict with None values for those keys — with no indication that any variable was missing.

Reproduction:

engine = YAMLTemplateEngine()
yaml_content = '''
test: {{ missing_var }}
'''
result = engine.load_string(yaml_content, {})  # Empty context
# Returns: {'test': None} instead of raising UndefinedError

Location:

  • File: src/cleveragents/actor/yaml_template_engine.py
  • Method: YAMLTemplateEngine.__init__() — Jinja2 SandboxedEnvironment construction (no undefined= kwarg set)
  • Method: YAMLTemplateEngine._render_and_parse() — template rendering call at template.render(**full_context)

Expected Behavior

Missing template variables should fail fast and loudly. Acceptable approaches (in order of preference):

  1. Strict mode (recommended): Configure the Jinja2 environment with undefined=StrictUndefined so that accessing any undefined variable raises jinja2.UndefinedError immediately during rendering.
  2. Configurable mode: Expose a strict: bool = True constructor parameter that toggles between StrictUndefined (default) and Undefined for callers that explicitly need lenient rendering.
  3. Descriptive placeholder: Use a custom Undefined subclass that renders to a clearly identifiable sentinel string (e.g., <UNDEFINED:missing_var>) rather than an empty string, so downstream YAML parsing does not silently produce None.

Acceptance Criteria

  • YAMLTemplateEngine.load_string() raises jinja2.UndefinedError (or a project-specific subclass) when the rendering context is missing a variable referenced in the template.
  • The error message clearly identifies the name of the missing variable.
  • Existing tests that pass a complete context continue to pass without modification.
  • If a configurable strict/lenient mode is implemented, the default is strict.
  • All public method argument validation guards are present and correct.
  • Full static typing is maintained; Pyright passes with no new errors.

Subtasks

  • Configure SandboxedEnvironment with undefined=StrictUndefined (or implement configurable mode)
  • Verify that _render_and_parse() propagates UndefinedError without suppressing it
  • Review all except clauses in YAMLTemplateEngine to ensure UndefinedError is not accidentally swallowed
  • Tests (Behave): Add BDD scenarios for missing-variable strict-mode behavior (@tdd_issue + @tdd_issue_<N> tags)
  • Tests (Robot): Add integration test for YAML template loading with missing variables
  • Tests (ASV): Add benchmark scenario if rendering path changes affect performance
  • Verify coverage ≥ 97% via nox -s coverage_report
  • Run nox (all default sessions), fix any errors

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • A Git commit is created where the first line of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation.
  • The commit is pushed to the remote on the branch matching the Branch in Metadata exactly.
  • The commit is submitted as a pull request to master, reviewed, and merged before this issue is marked done.
  • All nox stages pass.
  • Coverage ≥ 97%.

Supporting Information

  • Related issue: #7113BUG-HUNT: [error-handling] YAML template engine fails on deferred rendering with unhashable key error (different failure mode in the same engine)
  • Related issue: #6420BUG-HUNT: [consistency] YAMLTemplateEngine._postprocess_rendered_yaml() contains mutually exclusive conditions
  • Jinja2 docs: StrictUndefined
  • CONTRIBUTING.md: Fail-Fast Principles — "No Silent Failures: Avoid returning null or default values when an error condition exists"

Automated by CleverAgents Bot
Supervisor: Acting on behalf of: Bug Hunter | Agent: new-issue-creator

## Metadata - **Branch**: `bugfix/data-flow-yaml-template-engine-silent-none-missing-vars` - **Commit Message**: `fix(actor): raise UndefinedError for missing Jinja2 template variables in YAMLTemplateEngine` - **Milestone**: Backlog (no milestone — see backlog note below) - **Parent Epic**: TBD — orphan flag posted in comment > **Backlog note:** This issue was discovered during autonomous operation > on milestone v3.7.0. It does not block milestone completion and has been > placed in the backlog for human review and future milestone assignment. ## Background and Context The `YAMLTemplateEngine` in `src/cleveragents/actor/yaml_template_engine.py` uses a Jinja2 `SandboxedEnvironment` to render inline templates embedded in YAML configuration files. The environment is currently configured with Jinja2's default `Undefined` class, which silently renders missing variables as an empty string — which YAML then parses as `None`. This violates the project's **fail-fast** principle (CONTRIBUTING.md: *"No Silent Failures: Avoid returning null or default values when an error condition exists — raise exceptions or return explicit error types"*) and the **argument validation** mandate (*"All public and protected class methods must validate arguments as the first guard"*). ## Current Behavior When a YAML template references a variable that is absent from the rendering context, the Jinja2 engine silently substitutes an empty string. YAML then parses the empty value as `None`, and the caller receives a dict with `None` values for those keys — with no indication that any variable was missing. **Reproduction:** ```python engine = YAMLTemplateEngine() yaml_content = ''' test: {{ missing_var }} ''' result = engine.load_string(yaml_content, {}) # Empty context # Returns: {'test': None} instead of raising UndefinedError ``` **Location:** - File: `src/cleveragents/actor/yaml_template_engine.py` - Method: `YAMLTemplateEngine.__init__()` — Jinja2 `SandboxedEnvironment` construction (no `undefined=` kwarg set) - Method: `YAMLTemplateEngine._render_and_parse()` — template rendering call at `template.render(**full_context)` ## Expected Behavior Missing template variables should fail fast and loudly. Acceptable approaches (in order of preference): 1. **Strict mode (recommended):** Configure the Jinja2 environment with `undefined=StrictUndefined` so that accessing any undefined variable raises `jinja2.UndefinedError` immediately during rendering. 2. **Configurable mode:** Expose a `strict: bool = True` constructor parameter that toggles between `StrictUndefined` (default) and `Undefined` for callers that explicitly need lenient rendering. 3. **Descriptive placeholder:** Use a custom `Undefined` subclass that renders to a clearly identifiable sentinel string (e.g., `<UNDEFINED:missing_var>`) rather than an empty string, so downstream YAML parsing does not silently produce `None`. ## Acceptance Criteria - [ ] `YAMLTemplateEngine.load_string()` raises `jinja2.UndefinedError` (or a project-specific subclass) when the rendering context is missing a variable referenced in the template. - [ ] The error message clearly identifies the name of the missing variable. - [ ] Existing tests that pass a complete context continue to pass without modification. - [ ] If a configurable strict/lenient mode is implemented, the default is strict. - [ ] All public method argument validation guards are present and correct. - [ ] Full static typing is maintained; Pyright passes with no new errors. ## Subtasks - [ ] Configure `SandboxedEnvironment` with `undefined=StrictUndefined` (or implement configurable mode) - [ ] Verify that `_render_and_parse()` propagates `UndefinedError` without suppressing it - [ ] Review all `except` clauses in `YAMLTemplateEngine` to ensure `UndefinedError` is not accidentally swallowed - [ ] Tests (Behave): Add BDD scenarios for missing-variable strict-mode behavior (`@tdd_issue` + `@tdd_issue_<N>` tags) - [ ] Tests (Robot): Add integration test for YAML template loading with missing variables - [ ] Tests (ASV): Add benchmark scenario if rendering path changes affect performance - [ ] Verify coverage ≥ 97% via `nox -s coverage_report` - [ ] Run `nox` (all default sessions), fix any errors ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation. - The commit is pushed to the remote on the branch matching the **Branch** in Metadata exactly. - The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done. - All nox stages pass. - Coverage ≥ 97%. ## Supporting Information - Related issue: #7113 — `BUG-HUNT: [error-handling] YAML template engine fails on deferred rendering with unhashable key error` (different failure mode in the same engine) - Related issue: #6420 — `BUG-HUNT: [consistency] YAMLTemplateEngine._postprocess_rendered_yaml() contains mutually exclusive conditions` - Jinja2 docs: [`StrictUndefined`](https://jinja.palletsprojects.com/en/3.1.x/api/#jinja2.StrictUndefined) - CONTRIBUTING.md: Fail-Fast Principles — *"No Silent Failures: Avoid returning null or default values when an error condition exists"* --- **Automated by CleverAgents Bot** Supervisor: Acting on behalf of: Bug Hunter | Agent: new-issue-creator
Author
Owner

⚠️ Orphan Issue — Parent Epic Required

This issue was created by an automated agent and could not be automatically linked to a parent Epic. No open Epic for the actor/yaml_template_engine data-flow module was found in the open issues.

A search was performed across all open Type/Epic issues. The closest related issues are:

  • #7113BUG-HUNT: [error-handling] YAML template engine fails on deferred rendering with unhashable key error (also orphaned, same module)
  • #6420BUG-HUNT: [consistency] YAMLTemplateEngine._postprocess_rendered_yaml() contains mutually exclusive conditions (same module)

Action required: A maintainer must:

  1. Identify or create the appropriate parent Epic for actor/yaml_template_engine bugs
  2. Link this issue as a child by opening the parent Epic and adding this issue (#7126) under "depends on", OR by opening this issue and adding the parent under "blocks"
  3. Consider grouping #7113, #6420, and #7126 under the same parent Epic since they all affect YAMLTemplateEngine

Automated by CleverAgents Bot
Supervisor: Acting on behalf of: Bug Hunter | Agent: new-issue-creator

⚠️ **Orphan Issue — Parent Epic Required** This issue was created by an automated agent and could not be automatically linked to a parent Epic. No open Epic for the `actor/yaml_template_engine` data-flow module was found in the open issues. A search was performed across all open `Type/Epic` issues. The closest related issues are: - #7113 — `BUG-HUNT: [error-handling] YAML template engine fails on deferred rendering with unhashable key error` (also orphaned, same module) - #6420 — `BUG-HUNT: [consistency] YAMLTemplateEngine._postprocess_rendered_yaml() contains mutually exclusive conditions` (same module) **Action required:** A maintainer must: 1. Identify or create the appropriate parent Epic for `actor/yaml_template_engine` bugs 2. Link this issue as a child by opening the parent Epic and adding this issue (#7126) under **"depends on"**, OR by opening this issue and adding the parent under **"blocks"** 3. Consider grouping #7113, #6420, and #7126 under the same parent Epic since they all affect `YAMLTemplateEngine` --- **Automated by CleverAgents Bot** Supervisor: Acting on behalf of: Bug Hunter | Agent: new-issue-creator
Author
Owner

Verified — Critical data flow bug: YAML template engine silently returns None for missing variables. MoSCoW: Must-have. Priority: Critical.


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: project-owner-pool-supervisor

✅ **Verified** — Critical data flow bug: YAML template engine silently returns None for missing variables. MoSCoW: Must-have. Priority: Critical. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#7126
No description provided.