Skip to content

fix(frontend): validate edge source/target before adding connection - #14271

Open
minderm wants to merge 1 commit into
langflow-ai:mainfrom
minderm:fix/clean-edges-validation
Open

fix(frontend): validate edge source/target before adding connection#14271
minderm wants to merge 1 commit into
langflow-ai:mainfrom
minderm:fix/clean-edges-validation

Conversation

@minderm

@minderm minderm commented Jul 27, 2026

Copy link
Copy Markdown

Description

  • Added validation in cleanEdges to skip edges with missing source/target
  • Added unit tests for edge validation scenarios
  • Prevents edge rendering crash when nodes are deleted

Changed files

  • src/frontend/src/utils/reactflowUtils.ts — validation logic in cleanEdges
  • src/frontend/src/utils/__tests__/cleanEdges.test.ts — unit tests

How to test

  1. Open a flow with connected nodes
  2. Delete a node that is connected to other nodes
  3. Verify no crash occurs and edges are correctly removed

Checklist

  • Code follows project conventions (biome formatted)
  • Unit tests added/updated
  • Pre-commit hooks passed

Summary by CodeRabbit

  • Bug Fixes
    • Preserved connections to MCP tool parameters while their schemas are loading or incomplete.
    • Prevented valid MCP connections from being incorrectly removed when fields are temporarily hidden or unavailable.
    • Continued removing genuinely invalid connections for non-MCP components.
    • Added coverage for missing and empty MCP parameter definitions.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

MCP edge validation

Layer / File(s) Summary
Pending MCP edge handling
src/frontend/src/utils/reactflowUtils.ts, src/frontend/src/utils/__tests__/cleanEdges.test.ts
cleanEdges preserves MCP edges while parameter schemas are missing or empty, and hidden-field filtering exempts MCP targets.
MCP edge regression coverage
src/frontend/src/utils/__tests__/cleanEdges.test.ts
Tests cover pending MCP fields, empty input_types, hidden-field behavior, and broken-edge removal for non-MCP components.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: cristhianzl


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
Test Coverage For New Implementations ❌ Error cleanEdges.test.ts defines its own cleanEdges/filterHiddenFieldsEdges and never imports the production utils, so the MCP cases don't verify reactflowUtils.ts behavior. Import the exported cleanEdges/filterHiddenFieldsEdges from reactflowUtils.ts and run the MCP regression cases against that implementation.
Test Quality And Coverage ⚠️ Warning Tests reimplement cleanEdges/filterHiddenFieldsEdges locally and never import reactflowUtils.ts, so the MCP cases don’t validate production behavior. Import the exported helpers from reactflowUtils.ts and assert their outputs directly; remove the local duplicate so the MCP cases exercise real code.
Excessive Mock Usage Warning ⚠️ Warning FAIL: cleanEdges.test.ts reimplements cleanEdges, filterHiddenFieldsEdges, and JSON helpers locally instead of importing production code, so core behavior is mocked. Import the exported utils from reactflowUtils.ts and exercise them with real fixtures; keep mocks only for external deps, or add integration tests.
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is clear and relevant to the PR’s edge-validation changes in frontend cleanEdges logic.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Test File Naming And Structure ✅ Passed Frontend unit test is correctly named in tests/cleanEdges.test.ts, uses nested describe/it blocks, and covers positive/negative MCP and broken-edge cases.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 27, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/frontend/src/utils/__tests__/cleanEdges.test.ts`:
- Line 1000: Update the tests around the local cleanEdges helper to import and
invoke the exported production cleanEdges and filterHiddenFieldsEdges
implementations from reactflowUtils instead. Remove or bypass the duplicate
local implementations so the cases at all referenced locations validate
production behavior, including handlesMatch and advanced-field handling, rather
than only smoke-testing a divergent test helper.
- Line 106: Update the targetHandle extraction in the cleanEdges test to narrow
or cast edge.data to an object shape containing an optional targetHandle before
accessing the property, then retain TargetHandleType for the resulting value. Do
not access targetHandle directly while EdgeType.data remains unknown.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 30ba67a7-6107-4464-9f53-43ca467b7f7e

📥 Commits

Reviewing files that changed from the base of the PR and between ce17f02 and bb50af4.

📒 Files selected for processing (2)
  • src/frontend/src/utils/__tests__/cleanEdges.test.ts
  • src/frontend/src/utils/reactflowUtils.ts

// MCP server. Before the schema loads, dynamic fields may have show: false.
// Removing edges in that transient state causes false positives.
const isMcpComponent = targetNode.data.type === "MCPTools";
const targetHandle = _edge.data?.targetHandle as TargetHandleType | undefined;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C 3 'data\?: unknown|_edge\.data\?\.targetHandle' \
  src/frontend/src/utils/__tests__/cleanEdges.test.ts

Repository: langflow-ai/langflow

Length of output: 777


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file excerpt =="
sed -n '70,140p' src/frontend/src/utils/__tests__/cleanEdges.test.ts | cat -n

echo
echo "== tsconfig/frontend package type-check scripts =="
for f in package.json src/frontend/package.json tsconfig.json src/frontend/tsconfig.json; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    sed -n '1,220p' "$f"
  fi
done

echo
echo "== TypeScript availability and parser check =="
command -v tsc || true
node - <<'JS'
try {
  const ts = require('typescript')
  const source = `
interface EdgeType {
  selected?: boolean;
  animated?: boolean;
  data?: unknown;
}
const _edge: EdgeType = {};
const targetHandle = _edge.data?.targetHandle as string | undefined;
`
  const sf = ts.createSourceFile('probe.ts', source, ts.ScriptTarget.Latest, true)
  const program = ts.createProgram(['probe.ts'], {})
  const diagnostics = ts.getPreEmitDiagnostics(program)
  console.log(JSON.stringify({
    hasTs: true,
    diagnostics: diagnostics.map(d => ({
      code: d.code,
      message: ts.flattenDiagnosticMessageText(d.messageText, '\n'),
      start: d.file ? sf.getLineAndCharacterOfPosition(d.start) : null
    }))
  }, null, 2))
} catch (e) {
  console.log(JSON.stringify({hasTs: false, error: String(e && e.message || e)}, null, 2))
}
JS

Repository: langflow-ai/langflow

Length of output: 12300


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file excerpt =="
sed -n '70,140p' src/frontend/src/utils/__tests__/cleanEdges.test.ts | cat -n

echo
echo "== tsconfig/frontend package type-check scripts =="
for f in package.json src/frontend/package.json tsconfig.json src/frontend/tsconfig.json; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    sed -n '1,220p' "$f"
  fi
done

echo
echo "== Type narrowing probe =="
node - <<'JS'
const code = `_edge.data?.targetHandle`
console.log(`TypeScript optional-chaining narrowing behavior for data?: unknown cannot be reliably checked without TS compiler/tooling in this environment; the repository does expose data?: unknown upstream.`)
JS

Repository: langflow-ai/langflow

Length of output: 12366


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== cleanEdges test file size and imports near top =="
wc -l src/frontend/src/utils/__tests__/cleanEdges.test.ts
sed -n '1,26p' src/frontend/src/utils/__tests__/cleanEdges.test.ts | cat -n

echo
echo "== static probe: unknown data followed by optional property access in EdgeType =="
python3 - <<'PY'
from pathlib import Path
p = Path("src/frontend/src/utils/__tests__/cleanEdges.test.ts")
text = p.read_text()
print(EdgeType := text[text.find("interface EdgeType"): text.find("// Simplified filterHiddenFieldsEdges mock")])
print("data access line:", text[text.find("const targetHandle ="): text.find("const targetHandle =")+-1])
print("contains TargetHandleType import:", "TargetHandleType" in text[:text.find("_edge.data?.targetHandle")])
PY

Repository: langflow-ai/langflow

Length of output: 1533


Type edge.data before reading targetHandle.

EdgeType.data is still unknown, and the helper narrows it down before asserting TargetHandleType. Cast/narrow the optional chain instead, or give data a targetHandle?: TargetHandleType shape.

Proposed fix
-  const targetHandle = _edge.data?.targetHandle as TargetHandleType | undefined;
+  const targetHandle = (
+    _edge.data as { targetHandle?: TargetHandleType } | undefined
+  )?.targetHandle;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const targetHandle = _edge.data?.targetHandle as TargetHandleType | undefined;
const targetHandle = (
_edge.data as { targetHandle?: TargetHandleType } | undefined
)?.targetHandle;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/frontend/src/utils/__tests__/cleanEdges.test.ts` at line 106, Update the
targetHandle extraction in the cleanEdges test to narrow or cast edge.data to an
object shape containing an optional targetHandle before accessing the property,
then retain TargetHandleType for the resulting value. Do not access targetHandle
directly while EdgeType.data remains unknown.

targetHandle,
};

const result = cleanEdges([parserNode, mcpNode], [edge]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Run these cases against the exported implementation.

These tests call this file’s local cleanEdges (Line 120), not src/frontend/src/utils/reactflowUtils.ts’s exported function. The duplicate already diverges from production (handlesMatch and advanced-field handling), so the new cases do not prove the PR behavior. Import and invoke the production cleanEdges/filterHiddenFieldsEdges instead. As per coding guidelines, frontend tests must “verify meaningful behavior for new functionality rather than only smoke-testing it.”

Also applies to: 1074-1074, 1143-1143

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/frontend/src/utils/__tests__/cleanEdges.test.ts` at line 1000, Update the
tests around the local cleanEdges helper to import and invoke the exported
production cleanEdges and filterHiddenFieldsEdges implementations from
reactflowUtils instead. Remove or bypass the duplicate local implementations so
the cases at all referenced locations validate production behavior, including
handlesMatch and advanced-field handling, rather than only smoke-testing a
divergent test helper.

Source: Coding guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant