From 588de042fcc86ec7017673b11e5c2151b5b4fad0 Mon Sep 17 00:00:00 2001 From: nightcityblade Date: Sat, 1 Aug 2026 09:08:39 +0800 Subject: [PATCH] fix(docker): preserve single-url crawl failure details --- deploy/docker/api.py | 25 +++++++++++-------- .../docker/tests/test_api_crawl_failures.py | 24 ++++++++++++++++++ 2 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 deploy/docker/tests/test_api_crawl_failures.py diff --git a/deploy/docker/api.py b/deploy/docker/api.py index 1756b925f..22e061096 100644 --- a/deploy/docker/api.py +++ b/deploy/docker/api.py @@ -92,6 +92,15 @@ def _attach_declarative_hooks(crawler, hooks_config: dict) -> dict: logger = logging.getLogger(__name__) + +def _raise_for_crawl_failure(result): + if not result.success: + raise HTTPException( + status_code=status.HTTP_502_BAD_GATEWAY, + detail=result.error_message, + ) + + # --- Helper to get memory --- def _get_memory_mb(): try: @@ -147,11 +156,7 @@ async def handle_llm_qa( enforce_egress(browser_cfg) crawler = await get_crawler(browser_cfg) result = await crawler.arun(url) - if not result.success: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=result.error_message - ) + _raise_for_crawl_failure(result) content = result.markdown.fit_markdown or result.markdown.raw_markdown # Create prompt and get LLM response @@ -179,6 +184,8 @@ async def handle_llm_qa( ) return response.choices[0].message.content + except HTTPException: + raise except LLMProviderNotAllowed as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: @@ -389,11 +396,7 @@ async def handle_markdown_request( ) ) - if not result.success: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=result.error_message - ) + _raise_for_crawl_failure(result) return (result.markdown.raw_markdown if filter_type == FilterType.RAW @@ -1023,4 +1026,4 @@ async def _runner(): except HTTPException: await redis.delete(f"task:{task_id}") raise - return {"task_id": task_id} \ No newline at end of file + return {"task_id": task_id} diff --git a/deploy/docker/tests/test_api_crawl_failures.py b/deploy/docker/tests/test_api_crawl_failures.py new file mode 100644 index 000000000..6c8fa817f --- /dev/null +++ b/deploy/docker/tests/test_api_crawl_failures.py @@ -0,0 +1,24 @@ +import inspect +from types import SimpleNamespace + +import pytest +from fastapi import HTTPException + +from api import _raise_for_crawl_failure, handle_llm_qa, handle_markdown_request + + +def test_crawl_failure_is_reported_as_bad_gateway(): + result = SimpleNamespace(success=False, error_message="Blocked by anti-bot protection: challenge") + + with pytest.raises(HTTPException) as raised: + _raise_for_crawl_failure(result) + + assert raised.value.status_code == 502 + assert raised.value.detail == result.error_message + + +@pytest.mark.parametrize("handler", [handle_llm_qa, handle_markdown_request]) +def test_single_url_handlers_use_crawl_failure_mapping(handler): + source = inspect.getsource(handler) + assert "_raise_for_crawl_failure(result)" in source + assert handler is not handle_llm_qa or "except HTTPException:" in source