[PR #24846] feat: implement END node convergence validation for workflow #30822

Closed
opened 2026-02-21 20:48:17 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/langgenius/dify/pull/24846

State: closed
Merged: No


Related #23981

Summary

This PR implements END node convergence validation for workflows to ensure that multiple entry nodes in the same connected graph cannot point to different END nodes. This prevents runtime ambiguity about which END result should be the final workflow output.

Key Changes

Core Implementation

  • validateEndNodeConvergence function: New validation algorithm using DFS to detect connected components and check if multiple entry nodes in same graph point to different END nodes
  • Integration in use-checklist: Added validation to workflow checklist (workflow mode only, not chat mode)
  • Internationalization: Added error messages for validation failures

UI Improvements

  • Fixed checklist warning icon: Added shrink-0 class to prevent warning icons from being compressed when error messages span multiple lines

Testing

  • Comprehensive test suite: 15 test cases covering valid/invalid scenarios, edge cases, and real-world workflows
  • High coverage: 97.29% branch coverage achieved

Validation Rules with Examples

Valid Scenarios

1. Single Entry Node with Multiple END Nodes (Parallel Branches)

USER INPUT ──┬── END 1
             └── LLM ── END 2

Allowed: Single entry can have multiple parallel execution paths

2. Multiple Entry Nodes Converging to Same END Node

START ────┐
          ├── LLM ── END
TRIGGER ──┘

Allowed: Multiple entries converging to single END point

3. Multiple Entry Nodes in Different Connected Graphs

Graph 1: START ── END 1
Graph 2: TRIGGER ── LLM ── END 2

Allowed: Separate graphs can have their own END nodes

4. Complex Valid Scenario

TRIGGER1 ──┐
           ├── LLM1 ──┐
TRIGGER2 ──┘          ├── END
START ── LLM2 ────────┘

Allowed: All paths converge to same END

Invalid Scenarios

1. Multiple Entry Nodes with Different END Nodes (Same Graph)

START ── END 1
  │
  └── LLM ── END 2
      ↑
TRIGGER ──┘

Rejected: Connected graph with multiple entries pointing to different ENDs

2. Three Entry Nodes with Conflicting END Nodes

START ────┐
          ├── CODE ── END 1
TRIGGER1 ─┘
          ├── LLM ── END 2
TRIGGER2 ─┘

Rejected: Same connected component, different END destinations

3. Real-world Invalid Example

USER INPUT ── END 1
    │
    └── SHARED_PROCESSOR ──┬── END 2
                           └── END 3
                ↑
SCHEDULE_TRIGGER ──────────┘

Rejected: Multiple entry paths in same graph leading to different outputs

Technical Details

Algorithm

  1. Find all entry nodes (Start, TriggerSchedule, TriggerWebhook, TriggerPlugin)
  2. Build connected components using bidirectional DFS
  3. For each component with multiple entry nodes, trace all reachable END nodes
  4. Validate that all entry nodes in same component reach the same END node

Entry Node Types

  • BlockEnum.Start (user manual trigger)
  • BlockEnum.TriggerSchedule (scheduled execution)
  • BlockEnum.TriggerWebhook (webhook trigger)
  • BlockEnum.TriggerPlugin (plugin trigger)

Test Coverage Examples

Edge Cases Covered

  • Empty workflows: No validation needed
  • Single entry nodes: Always valid regardless of END count
  • Disconnected entry nodes: Each treated as separate component
  • Circular references: Handled without infinite loops
  • No END nodes: Valid scenario (incomplete workflow)

Real-world Scenarios

  • Complex branching workflows: IF/ELSE conditions with multiple paths
  • Multi-trigger workflows: Schedule + Webhook + Plugin triggers
  • Mixed entry types: Start + Trigger combinations
  • Deep workflow chains: Long execution paths with multiple decision points

Testing Strategy

  • Unit tests: Isolated validation function testing
  • Integration scenarios: Real workflow patterns
  • Edge cases: Empty workflows, circular references, disconnected nodes
  • Backward compatibility: Ensures existing valid workflows continue to work

Files Modified

  • app/components/workflow/utils/workflow.ts: Core validation logic (+91 lines)
  • app/components/workflow/hooks/use-checklist.ts: Integration point (+9 lines)
  • app/components/workflow/header/checklist.tsx: UI fix for warning icons (2 changes)
  • app/components/workflow/utils/end-node-convergence.spec.ts: Test suite (+354 lines, new file)

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran dev/reformat(backend) and cd web && npx lint-staged(frontend) to appease the lint gods
**Original Pull Request:** https://github.com/langgenius/dify/pull/24846 **State:** closed **Merged:** No --- Related #23981 ## Summary This PR implements END node convergence validation for workflows to ensure that multiple entry nodes in the same connected graph cannot point to different END nodes. This prevents runtime ambiguity about which END result should be the final workflow output. ## Key Changes ### Core Implementation - **validateEndNodeConvergence function**: New validation algorithm using DFS to detect connected components and check if multiple entry nodes in same graph point to different END nodes - **Integration in use-checklist**: Added validation to workflow checklist (workflow mode only, not chat mode) - **Internationalization**: Added error messages for validation failures ### UI Improvements - **Fixed checklist warning icon**: Added `shrink-0` class to prevent warning icons from being compressed when error messages span multiple lines ### Testing - **Comprehensive test suite**: 15 test cases covering valid/invalid scenarios, edge cases, and real-world workflows - **High coverage**: 97.29% branch coverage achieved ## Validation Rules with Examples ### ✅ Valid Scenarios #### 1. Single Entry Node with Multiple END Nodes (Parallel Branches) ``` USER INPUT ──┬── END 1 └── LLM ── END 2 ``` **Allowed**: Single entry can have multiple parallel execution paths #### 2. Multiple Entry Nodes Converging to Same END Node ``` START ────┐ ├── LLM ── END TRIGGER ──┘ ``` **Allowed**: Multiple entries converging to single END point #### 3. Multiple Entry Nodes in Different Connected Graphs ``` Graph 1: START ── END 1 Graph 2: TRIGGER ── LLM ── END 2 ``` **Allowed**: Separate graphs can have their own END nodes #### 4. Complex Valid Scenario ``` TRIGGER1 ──┐ ├── LLM1 ──┐ TRIGGER2 ──┘ ├── END START ── LLM2 ────────┘ ``` **Allowed**: All paths converge to same END ### ❌ Invalid Scenarios #### 1. Multiple Entry Nodes with Different END Nodes (Same Graph) ``` START ── END 1 │ └── LLM ── END 2 ↑ TRIGGER ──┘ ``` **Rejected**: Connected graph with multiple entries pointing to different ENDs #### 2. Three Entry Nodes with Conflicting END Nodes ``` START ────┐ ├── CODE ── END 1 TRIGGER1 ─┘ ├── LLM ── END 2 TRIGGER2 ─┘ ``` **Rejected**: Same connected component, different END destinations #### 3. Real-world Invalid Example ``` USER INPUT ── END 1 │ └── SHARED_PROCESSOR ──┬── END 2 └── END 3 ↑ SCHEDULE_TRIGGER ──────────┘ ``` **Rejected**: Multiple entry paths in same graph leading to different outputs ## Technical Details ### Algorithm 1. Find all entry nodes (Start, TriggerSchedule, TriggerWebhook, TriggerPlugin) 2. Build connected components using bidirectional DFS 3. For each component with multiple entry nodes, trace all reachable END nodes 4. Validate that all entry nodes in same component reach the same END node ### Entry Node Types - `BlockEnum.Start` (user manual trigger) - `BlockEnum.TriggerSchedule` (scheduled execution) - `BlockEnum.TriggerWebhook` (webhook trigger) - `BlockEnum.TriggerPlugin` (plugin trigger) ## Test Coverage Examples ### Edge Cases Covered - **Empty workflows**: No validation needed - **Single entry nodes**: Always valid regardless of END count - **Disconnected entry nodes**: Each treated as separate component - **Circular references**: Handled without infinite loops - **No END nodes**: Valid scenario (incomplete workflow) ### Real-world Scenarios - **Complex branching workflows**: IF/ELSE conditions with multiple paths - **Multi-trigger workflows**: Schedule + Webhook + Plugin triggers - **Mixed entry types**: Start + Trigger combinations - **Deep workflow chains**: Long execution paths with multiple decision points ## Testing Strategy - **Unit tests**: Isolated validation function testing - **Integration scenarios**: Real workflow patterns - **Edge cases**: Empty workflows, circular references, disconnected nodes - **Backward compatibility**: Ensures existing valid workflows continue to work ## Files Modified - `app/components/workflow/utils/workflow.ts`: Core validation logic (+91 lines) - `app/components/workflow/hooks/use-checklist.ts`: Integration point (+9 lines) - `app/components/workflow/header/checklist.tsx`: UI fix for warning icons (2 changes) - `app/components/workflow/utils/end-node-convergence.spec.ts`: Test suite (+354 lines, new file) ## Checklist - [x] This change requires a documentation update, included: [Dify Document](https://github.com/langgenius/dify-docs) - [x] I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!) - [x] I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change. - [x] I've updated the documentation accordingly. - [x] I ran `dev/reformat`(backend) and `cd web && npx lint-staged`(frontend) to appease the lint gods
yindo added the pull-request label 2026-02-21 20:48:17 -05:00
yindo closed this issue 2026-02-21 20:48:18 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#30822