Repository: confident-ai/deepeval
Issue: TypeError in DAG Nodes Without evaluation_params
Root cause: Validation Gap

**Describe the bug**
When creating DAG structures with nested `TaskNode` instances (TaskNode as child of another TaskNode) without explicitly setting `evaluation_params` on the child TaskNode, a `TypeError: 'NoneType' object is not iterable` occurs during metric evaluation.
The error occurs in DeepEval's DAG execution when a child `TaskNode` (nested under another TaskNode) doesn't have `evaluation_params` explicitly set. The library expects `evaluation_params` to be a list, but when not provided, it defaults to `None`, causing iteration errors.

## Expected Behavior
Error should be clear, not just runtime type check error. It would be perfect if we would have also an ability to pass extraction to nested TaskNode

### Error Stack Trace
```
TypeError: 'NoneType' object is not iterable

File "deepeval/metrics/dag/nodes.py", line 296, in _execute
    for param in self.evaluation_params:
```

## Environment
- **DeepEval version**: Latest (as of report date)
- **Python version**: 3.13
- **Operating System**: macOS


**Additional context**
Add any other context about the problem here.

```
from dotenv import load_dotenv
from deepeval.test_case import LLMTestCase, LLMTestCaseParams
from deepeval.metrics.dag import (
    DeepAcyclicGraph,
    TaskNode,
    BinaryJudgementNode,
    VerdictNode,
)
from deepeval.metrics import DAGMetric

# Load environment variables
load_dotenv()

# Create the DAG structure
correct_letters_node = BinaryJudgementNode(
    criteria="Does first heading has i as first letter?",
    children=[
        VerdictNode(verdict=False, score=0),
        VerdictNode(verdict=True,score=1),
    ],
)
extract_letter_node= TaskNode(
    instructions="Extract first heading",
    output_label="first heading",
    children=[correct_letters_node],
    evaluation_params=[]
)

correct_order_node = BinaryJudgementNode(
    criteria="Are the summary headings in the correct order: 'intro' => 'body' => 'conclusion'?",
    children=[
        VerdictNode(verdict=False, score=0),
        VerdictNode(verdict=True, child=correct_letters_node),
    ],
)

correct_headings_node = BinaryJudgementNode(
    criteria="Does the summary headings contain all three: 'intro', 'body', and 'conclusion'?",
    children=[
        VerdictNode(verdict=False, score=0),
        VerdictNode(verdict=True, child=correct_order_node),
    ],
)

extract_headings_node = TaskNode(
    instructions="Extract all headings in `actual_output`",
    evaluation_params=[LLMTestCaseParams.ACTUAL_OUTPUT],
    output_label="Summary headings",
    children=[correct_headings_node, correct_order_node, extract_letter_node],
)

# Create the DAG
dag = DeepAcyclicGraph(root_nodes=[extract_headings_node])

# Test case
test_case = LLMTestCase(
    input="Summarize this team meeting with proper structure using intro, body, and conclusion headings:",
    actual_output="""
Intro:
Alice outlined the agenda: product updates, blockers, and marketing alignment.

Body:
Bob reported performance issues being optimized, with fixes expected by Friday. Charlie requested finalized messaging by Monday for marketing preparation. Bob confirmed an early stable build would be ready.

Conclusion:
The team aligned on next steps: engineering finalizing fixes, marketing preparing content, and a follow-up sync scheduled for Wednesday.
"""
)

if __name__ == "__main__":
    # Create DAG metric
    format_correctness = DAGMetric( name="Format Correctness", dag=dag)

    print("Testing DAG...")

    try:
        format_correctness.measure(test_case)
        print(f"Score: {format_correctness.score}")
        print(f"Success: {format_correctness.success}")
        print(f"Reason: {format_correctness.reason}")
    except Exception as e:
        print(f"Error: {e}")
```

There is a workaround to run without error, if we will put evaluation_params=[] inside TaskNode. But we will not get in this tasknode anything extracted in root tasknode :)


Hey @hazyone releasing a new version right now that fixes this :)

@hazyone it is fixed btw, closing this