"""Shared utilities for handling Pydantic validation errors.""" import json from pydantic import ValidationError from pydantic_core import ErrorDetails from ninja.errors import HttpError def format_validation_error(error: ErrorDetails) -> str: """Format a Pydantic validation error into a user-friendly message. Args: error: A Pydantic error details dictionary containing 'msg', 'type', 'ctx', etc. Returns: A user-friendly error message string. """ msg = error.get("msg") or "Invalid value" error_type = error.get("type") or "" # Handle common validation types with friendly messages if error_type == "enum": ctx = error.get("ctx", {}) expected = ctx.get("expected", "") if ctx else "" return f"Please select a valid option{': ' + expected if expected else ''}" elif error_type == "literal_error": # Literal errors (like Literal["active", "inactive"]) return msg.replace("Input should be ", "Please enter ") elif error_type == "missing": return "This field is required" elif error_type == "string_type": return "Please enter a valid string" elif error_type == "int_type": return "Please enter a valid int" elif error_type == "int_parsing": return "Please enter a valid int" elif error_type == "float_type": return "Please enter a valid float" elif error_type == "float_parsing": return "Please enter a valid float" elif error_type == "value_error": # Strip "Value error, " prefix from custom validator messages return msg.replace("Value error, ", "") else: # Default: use the message from Pydantic but clean it up return msg.replace("Input should be ", "Please enter ").replace("Value error, ", "") def handle_validation_error(e: ValidationError) -> None: """Convert a Pydantic ValidationError into a structured HttpError. This function transforms Pydantic validation errors into a JSON structure that the frontend expects for displaying field-level errors. Args: e: The Pydantic ValidationError to handle. Raises: HttpError: Always raises a 400 error with structured JSON containing type, field_errors, and message fields. """ # Transform Pydantic validation errors into user-friendly format field_errors: dict[str, list[str]] = {} for error in e.errors(): # Get the field name from location tuple loc = error.get("loc", ()) field = str(loc[-1]) if loc else "root" # Format the error message friendly_msg = format_validation_error(error) if field not in field_errors: field_errors[field] = [] field_errors[field].append(friendly_msg) # Return structured error for frontend parsing error_response = { "type": "validation_error", "field_errors": field_errors, "message": "Please correct the errors below", } raise HttpError(400, json.dumps(error_response))