diff --git a/openbb_platform/core/openbb_core/api/exception_handlers.py b/openbb_platform/core/openbb_core/api/exception_handlers.py index 85abf39d9da6..55b4a11f3930 100644 --- a/openbb_platform/core/openbb_core/api/exception_handlers.py +++ b/openbb_platform/core/openbb_core/api/exception_handlers.py @@ -91,16 +91,27 @@ async def validation( ) except Exception: errors = error.errors if hasattr(error, "errors") else error - all_in_query = all( - loc in query_params - for err in errors # ty: ignore[not-iterable] - for loc in err.get("loc", ()) - ) - if "QueryParams" in error.title and all_in_query: + if "QueryParams" in error.title: detail = [ { **{k: v for k, v in err.items() if k != "ctx"}, - "loc": ("query",) + err.get("loc", ()), + "loc": ( + ("query",) + err.get("loc", ()) + if ( + # Fetcher QueryParams validation reports absent + # fields without a transport source. Preserve an + # explicit source such as "body". + ( + err.get("type") == "missing" + and len(err.get("loc", ())) == 1 + ) + or all( + loc in query_params + for loc in err.get("loc", ()) + ) + ) + else err.get("loc", ()) + ), } for err in errors # ty: ignore[not-iterable] ] diff --git a/openbb_platform/core/tests/api/test_exception_handlers.py b/openbb_platform/core/tests/api/test_exception_handlers.py index 813f48929e0d..f0cf85ee4d11 100644 --- a/openbb_platform/core/tests/api/test_exception_handlers.py +++ b/openbb_platform/core/tests/api/test_exception_handlers.py @@ -184,3 +184,41 @@ async def test_unauthorized_handler(monkeypatch): err = UnauthorizedError("nope") resp = await ExceptionHandlers.unauthorized(_make_request(), err) assert resp.status_code == 502 + + +@pytest.mark.asyncio +async def test_validation_handler_missing_fetcher_param_is_routed_to_query(monkeypatch): + monkeypatch.setattr( + "openbb_core.api.exception_handlers.Env", type("E", (), {"DEBUG_MODE": False}) + ) + + class FetcherQueryParams(BaseModel): + category: str + + try: + FetcherQueryParams() # type: ignore[call-arg] + except ValidationError as error: + response = await ExceptionHandlers.validation(_make_request(), error) + else: + raise AssertionError("FetcherQueryParams should require category") + + assert response.status_code == 422 + assert json.loads(response.body)["detail"][0]["loc"] == ["query", "category"] + + +@pytest.mark.asyncio +async def test_validation_handler_preserves_explicit_body_location(monkeypatch): + monkeypatch.setattr( + "openbb_core.api.exception_handlers.Env", type("E", (), {"DEBUG_MODE": False}) + ) + + class QueryParamsError(Exception): + title = "QueryParams" + + def errors(self, include_url=False): + return [{"type": "missing", "loc": ("body", "category"), "msg": "Field required"}] + + response = await ExceptionHandlers.validation(_make_request(), QueryParamsError("bad")) # type: ignore[arg-type] + + assert response.status_code == 422 + assert json.loads(response.body)["detail"][0]["loc"] == ["body", "category"]