fix: make serialization errors in component update show up in the UI (#5332)

* feat: Add SerializationError exception for improved error handling during data serialization

- Introduced a new SerializationError class to handle errors when serializing data to JSON.
- The class provides detailed error messages based on the type of serialization issue encountered, including async function handling and unsupported object types.
- Enhances the robustness of the application by providing clearer feedback for serialization-related errors.

* fix: Improve error handling in custom component update to include SerializationError
This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-12-18 15:36:55 -03:00 committed by GitHub
commit 0c08bed713
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 68 additions and 14 deletions

View file

@ -7,16 +7,8 @@ from typing import TYPE_CHECKING, Annotated
from uuid import UUID
import sqlalchemy as sa
from fastapi import (
APIRouter,
BackgroundTasks,
Body,
Depends,
HTTPException,
Request,
UploadFile,
status,
)
from fastapi import APIRouter, BackgroundTasks, Body, Depends, HTTPException, Request, UploadFile, status
from fastapi.encoders import jsonable_encoder
from loguru import logger
from sqlmodel import select
@ -35,6 +27,7 @@ from langflow.api.v1.schemas import (
from langflow.custom.custom_component.component import Component
from langflow.custom.utils import build_custom_component_template, get_instance_name, update_component_build_config
from langflow.exceptions.api import APIException, InvalidChatInputError
from langflow.exceptions.serialization import SerializationError
from langflow.graph.graph.base import Graph
from langflow.graph.schema import RunOutputs
from langflow.helpers.flow import get_flow_by_id_or_endpoint_name
@ -46,9 +39,7 @@ from langflow.services.auth.utils import api_key_security, get_current_active_us
from langflow.services.cache.utils import save_uploaded_file
from langflow.services.database.models.flow import Flow
from langflow.services.database.models.flow.model import FlowRead
from langflow.services.database.models.flow.utils import (
get_all_webhook_components_in_flow,
)
from langflow.services.database.models.flow.utils import get_all_webhook_components_in_flow
from langflow.services.database.models.user.model import User, UserRead
from langflow.services.deps import get_session_service, get_settings_service, get_task_service, get_telemetry_service
from langflow.services.settings.feature_flags import FEATURE_FLAGS
@ -605,6 +596,9 @@ async def custom_component_update(
Returns:
dict: The updated custom component node.
Raises:
HTTPException: If there's an error building or updating the component
SerializationError: If there's an error serializing the component to JSON
"""
try:
component = Component(_code=code_request.code)
@ -649,7 +643,11 @@ async def custom_component_update(
except Exception as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return component_node
try:
return jsonable_encoder(component_node)
except Exception as exc:
raise SerializationError.from_exception(exc, data=component_node) from exc
@router.get("/config", response_model=ConfigResponse)

View file

@ -0,0 +1,56 @@
from typing import Any
from fastapi import HTTPException, status
class SerializationError(HTTPException):
"""Exception raised when there are errors serializing data to JSON."""
def __init__(
self,
detail: str,
original_error: Exception | None = None,
data: Any = None,
status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR,
) -> None:
super().__init__(status_code=status_code, detail=detail)
self.original_error = original_error
self.data = data
@classmethod
def from_exception(cls, exc: Exception, data: Any = None) -> "SerializationError":
"""Create a SerializationError from an existing exception."""
errors = exc.args[0] if exc.args else []
if isinstance(errors, list):
for error in errors:
if isinstance(error, TypeError):
if "'coroutine'" in str(error):
return cls(
detail=(
"The component contains async functions that need to be awaited. Please add 'await' "
"before any async function calls in your component code."
),
original_error=exc,
data=data,
)
if "vars()" in str(error):
return cls(
detail=(
"The component contains objects that cannot be converted to JSON. Please ensure all "
"properties and return values in your component are basic Python types like strings, "
"numbers, lists, or dictionaries."
),
original_error=exc,
data=data,
)
# Generic error for other cases
return cls(
detail=(
"The component returned invalid data. Please check that all values in your component (properties, "
"return values, etc.) are basic Python types that can be converted to JSON."
),
original_error=exc,
data=data,
)