Skip to content

fix: ValidationError reduction on OSS and Desktop#12920

Open
olayinkaadelakun wants to merge 4 commits intorelease-1.10.0from
LE-1031
Open

fix: ValidationError reduction on OSS and Desktop#12920
olayinkaadelakun wants to merge 4 commits intorelease-1.10.0from
LE-1031

Conversation

@olayinkaadelakun
Copy link
Copy Markdown
Collaborator

@olayinkaadelakun olayinkaadelakun commented Apr 28, 2026

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Upload flow endpoint now properly validates endpoint names and returns a clear 422 error instead of crashing
    • Trace summaries now accept both structured data and text formats for input and output fields
  • Tests

    • Added validation tests for endpoint names during flow uploads
    • Added serialization tests for trace data with various input/output formats

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dcd716c6-01b7-487d-a4b6-a22e90c8c038

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR introduces validation error handling in the flow upload endpoint to return HTTP 422 for Pydantic validation failures, and expands the TraceSummaryRead model to accept string values for input and output fields alongside dictionaries. Tests validate the new validation behavior and trace model flexibility.

Changes

Cohort / File(s) Summary
Flow Upload Validation
src/backend/base/langflow/api/v1/flows.py, src/backend/tests/unit/api/v1/test_flows.py
Added explicit pydantic.ValidationError catching during FlowListCreate construction in upload_file to return HTTP 422 responses instead of unhandled errors. Two new unit tests validate that dotted endpoint_name values are rejected with 422 status and that valid formats are accepted without errors.
Trace Model Type Expansion
src/backend/base/langflow/services/database/models/traces/model.py, src/backend/tests/unit/services/database/models/traces/test_enum_serialization.py
Widened TraceSummaryRead.input and output field types from dict[str, Any] | None to dict[str, Any] | str | None to accept both structured objects and string representations. Added comprehensive regression tests covering dict, string, sentinel strings, and None values for these fields.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Important

Pre-merge checks failed

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

❌ Failed checks (1 error, 3 warnings)

Check name Status Explanation Resolution
Test Coverage For New Implementations ❌ Error Test coverage is incomplete: missing symmetric test for output field, weak assertions in upload flow test, and missing isinstance checks in flows.py implementation. Add test_should_accept_arbitrary_string_as_output test, strengthen assertions to assert HTTP_201_CREATED, and add isinstance type checks in flows.py before data operations.
Docstring Coverage ⚠️ Warning Docstring coverage is 35.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Quality And Coverage ⚠️ Warning Test suite has weak assertions that pass for any non-500/422 status code, missing symmetric coverage for widened output field type, and lacks edge case tests for non-mapping payloads that could cause unhandled TypeErrors returning 500 instead of 422. Strengthen success assertions to explicitly check HTTP 201 with response structure validation, add test_should_accept_arbitrary_string_as_output method, and add tests for non-mapping payload rejection with proper 422 responses.
Test File Naming And Structure ⚠️ Warning Test files lack sufficient assertion strength and symmetric coverage for newly widened fields. Strengthen assertion in test_upload_flow_accepts_valid_endpoint_name to assert HTTP_201_CREATED and add missing test_should_accept_arbitrary_string_as_output test.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: ValidationError reduction on OSS and Desktop' directly aligns with the main changes, which include explicit ValidationError handling in flow uploads and type widening in trace models to reduce validation failures.
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.
Excessive Mock Usage Warning ✅ Passed Test files demonstrate appropriate minimal mock usage with real object instantiation and genuine HTTP requests rather than mocking core logic.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch LE-1031

Warning

Review ran into problems

🔥 Problems

Timed out fetching pipeline failures after 30000ms


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 and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 28, 2026

Migration Validation Passed

All migrations follow the Expand-Contract pattern correctly.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 53.82%. Comparing base (2860e0e) to head (e861978).
⚠️ Report is 11 commits behind head on release-1.10.0.

Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##           release-1.10.0   #12920      +/-   ##
==================================================
- Coverage           53.82%   53.82%   -0.01%     
==================================================
  Files                2045     2051       +6     
  Lines              185870   187236    +1366     
  Branches            27938    26628    -1310     
==================================================
+ Hits               100041   100771     +730     
- Misses              84728    85355     +627     
- Partials             1101     1110       +9     
Flag Coverage Δ
backend 57.04% <100.00%> (+0.13%) ⬆️
frontend 54.00% <ø> (-0.02%) ⬇️
lfx 49.75% <ø> (-0.11%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/backend/base/langflow/api/v1/flows.py 52.30% <100.00%> (-0.71%) ⬇️
.../langflow/services/database/models/traces/model.py 90.25% <100.00%> (ø)

... and 149 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 28, 2026

Build successful! ✅
Deploying docs draft.
Deploy successful! View draft

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 28, 2026

Frontend Unit Test Coverage Report

Coverage Summary

Lines Statements Branches Functions
Coverage: 36%
36.22% (42132/116296) 67.84% (5784/8525) 36.27% (970/2674)

Unit Test Results

Tests Skipped Failures Errors Time
4095 0 💤 0 ❌ 0 🔥 7m 33s ⏱️

@olayinkaadelakun olayinkaadelakun changed the base branch from main to release-1.10.0 April 28, 2026 20:23
@olayinkaadelakun
Copy link
Copy Markdown
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions github-actions Bot added the bug Something isn't working label Apr 28, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/backend/base/langflow/api/v1/flows.py`:
- Around line 441-448: The handler assumes 'data' is a mapping which causes a
TypeError when uploaded JSON is a list or scalar; update the block around
FlowListCreate / FlowCreate and normalize_code_for_import to first validate that
data is a dict (e.g., isinstance(data, dict)) and if not return/raise an
HTTPException(status_code=422) with a clear message, otherwise proceed with the
existing "flows" in data branching and construction of FlowListCreate/FlowCreate
so that non-object payloads are handled before any ** unpacking occurs and the
existing ValidationError catch still applies.

In `@src/backend/tests/unit/api/v1/test_flows.py`:
- Around line 676-694: The test test_upload_flow_accepts_valid_endpoint_name
currently only asserts the response is not 500 or 422 which can hide other
failures; change it to assert the explicit expected success status (e.g.,
response.status_code == status.HTTP_200_OK or HTTP_201_CREATED depending on the
API) and validate basic response shape by checking the JSON payload contains
expected keys (parse response.json() and assert presence/values for keys like
"folder_name" or a list of uploaded flows or a success flag). Locate the
client.post call and replace the negative assertions with a positive status
assertion and one or two lightweight JSON checks to confirm the upload
succeeded.

In
`@src/backend/tests/unit/services/database/models/traces/test_enum_serialization.py`:
- Around line 165-167: Add a symmetric test to cover arbitrary-string values for
the output field: create a new test (e.g.,
test_should_accept_arbitrary_string_as_output) that constructs
TraceSummaryRead(**{**_TRACE_SUMMARY_DEFAULTS, "output": "plain string"}) and
asserts summary.output == "plain string"; this mirrors the existing
test_should_accept_arbitrary_string_as_input and ensures the widened type for
output (str | dict | None) accepts plain strings without regression.
🪄 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

Run ID: 3a239f74-f39c-4293-b062-b1a1638bfae9

📥 Commits

Reviewing files that changed from the base of the PR and between c8abc0e and defac4c.

📒 Files selected for processing (4)
  • src/backend/base/langflow/api/v1/flows.py
  • src/backend/base/langflow/services/database/models/traces/model.py
  • src/backend/tests/unit/api/v1/test_flows.py
  • src/backend/tests/unit/services/database/models/traces/test_enum_serialization.py

Comment on lines +441 to +448
try:
if "flows" in data:
data = {**data, "flows": [normalize_code_for_import(f) for f in data["flows"]]}
flow_list = FlowListCreate(**data)
else:
flow_list = FlowListCreate(flows=[FlowCreate(**normalize_code_for_import(data))])
except ValidationError as e:
raise HTTPException(status_code=422, detail=str(e)) from e
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.

⚠️ Potential issue | 🟠 Major

Handle non-object upload payloads to avoid fallback 500s

At Line 442, "flows" in data assumes data is a mapping. If the uploaded JSON is a list/scalar, the else branch can raise TypeError (** on non-mapping), which bypasses this ValidationError handler and can still return 500.

Proposed fix
     # Normalise code fields: if exported with code-as-lines format, rejoin to
     # strings before creating the Pydantic models so the DB always stores strings.
     try:
+        if not isinstance(data, dict):
+            raise HTTPException(status_code=422, detail="Invalid payload: expected a JSON object")
         if "flows" in data:
+            if not isinstance(data["flows"], list):
+                raise HTTPException(status_code=422, detail="Invalid payload: 'flows' must be a list")
             data = {**data, "flows": [normalize_code_for_import(f) for f in data["flows"]]}
             flow_list = FlowListCreate(**data)
         else:
             flow_list = FlowListCreate(flows=[FlowCreate(**normalize_code_for_import(data))])
     except ValidationError as e:
         raise HTTPException(status_code=422, detail=str(e)) from e
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/api/v1/flows.py` around lines 441 - 448, The
handler assumes 'data' is a mapping which causes a TypeError when uploaded JSON
is a list or scalar; update the block around FlowListCreate / FlowCreate and
normalize_code_for_import to first validate that data is a dict (e.g.,
isinstance(data, dict)) and if not return/raise an
HTTPException(status_code=422) with a clear message, otherwise proceed with the
existing "flows" in data branching and construction of FlowListCreate/FlowCreate
so that non-object payloads are handled before any ** unpacking occurs and the
existing ValidationError catch still applies.

Comment on lines +676 to +694
async def test_upload_flow_accepts_valid_endpoint_name(client: AsyncClient, logged_in_headers):
"""Endpoint names with only letters, numbers, hyphens, and underscores are accepted."""
import json

flow_data = {
"name": "neuro-vision",
"data": {},
"endpoint_name": "neuro-vision-planning_phase1",
}
file_content = json.dumps({"folder_name": "proj", "flows": [flow_data]})

response = await client.post(
"api/v1/flows/upload/",
files={"file": ("flows.json", file_content, "application/json")},
headers=logged_in_headers,
)
assert response.status_code != status.HTTP_500_INTERNAL_SERVER_ERROR
assert response.status_code != status.HTTP_422_UNPROCESSABLE_ENTITY

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.

⚠️ Potential issue | 🟠 Major

Strengthen the success assertion to prevent false positives

At Lines 692-693, != 500 and != 422 can still pass for other failures. Please assert the expected success code (and ideally basic response shape) for a valid payload.

Proposed fix
     response = await client.post(
         "api/v1/flows/upload/",
         files={"file": ("flows.json", file_content, "application/json")},
         headers=logged_in_headers,
     )
-    assert response.status_code != status.HTTP_500_INTERNAL_SERVER_ERROR
-    assert response.status_code != status.HTTP_422_UNPROCESSABLE_ENTITY
+    assert response.status_code == status.HTTP_201_CREATED
+    result = response.json()
+    assert isinstance(result, list)
+    assert len(result) == 1
+    assert result[0]["endpoint_name"] == "neuro-vision-planning_phase1"

Based on learnings: Applies to **/test_*.py : For API endpoints, verify both success and error response testing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/tests/unit/api/v1/test_flows.py` around lines 676 - 694, The test
test_upload_flow_accepts_valid_endpoint_name currently only asserts the response
is not 500 or 422 which can hide other failures; change it to assert the
explicit expected success status (e.g., response.status_code ==
status.HTTP_200_OK or HTTP_201_CREATED depending on the API) and validate basic
response shape by checking the JSON payload contains expected keys (parse
response.json() and assert presence/values for keys like "folder_name" or a list
of uploaded flows or a success flag). Locate the client.post call and replace
the negative assertions with a positive status assertion and one or two
lightweight JSON checks to confirm the upload succeeded.

Comment on lines +165 to +167
def test_should_accept_arbitrary_string_as_input(self):
summary = TraceSummaryRead(**{**_TRACE_SUMMARY_DEFAULTS, "input": "plain string"})
assert summary.input == "plain string"
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.

⚠️ Potential issue | 🟡 Minor

Add the symmetric arbitrary-string case for output.

Line 165 adds arbitrary string coverage for input, but output (also widened to str | dict | None) doesn’t have the same regression guard.

Suggested test addition
 class TestTraceSummaryReadIoFields:
@@
     def test_should_accept_arbitrary_string_as_input(self):
         summary = TraceSummaryRead(**{**_TRACE_SUMMARY_DEFAULTS, "input": "plain string"})
         assert summary.input == "plain string"
 
+    def test_should_accept_arbitrary_string_as_output(self):
+        summary = TraceSummaryRead(**{**_TRACE_SUMMARY_DEFAULTS, "output": "plain string"})
+        assert summary.output == "plain string"
+
     def test_should_default_input_and_output_to_none(self):
         summary = TraceSummaryRead(**_TRACE_SUMMARY_DEFAULTS)
         assert summary.input is None
         assert summary.output is None

As per coding guidelines: “Verify tests cover both positive and negative scenarios where appropriate.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/backend/tests/unit/services/database/models/traces/test_enum_serialization.py`
around lines 165 - 167, Add a symmetric test to cover arbitrary-string values
for the output field: create a new test (e.g.,
test_should_accept_arbitrary_string_as_output) that constructs
TraceSummaryRead(**{**_TRACE_SUMMARY_DEFAULTS, "output": "plain string"}) and
asserts summary.output == "plain string"; this mirrors the existing
test_should_accept_arbitrary_string_as_input and ensures the widened type for
output (str | dict | None) accepts plain strings without regression.

@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Apr 29, 2026
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