{"record":{"id":"4bd9c4e23dd763f7","repo":"unclecode/crawl4ai","slug":"str-e-4bd9c4","errorCode":null,"errorMessage":"str(e)","messagePattern":"str\\(e\\)","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"deploy/docker/monitor_routes.py","lineNumber":23,"sourceCode":"from monitor import get_monitor\nfrom auth import require_admin\nimport logging\nimport asyncio\nimport json\n\nlogger = logging.getLogger(__name__)\nrouter = APIRouter(prefix=\"/monitor\", tags=[\"monitor\"])\n\n\n@router.get(\"/health\")\nasync def get_health():\n    \"\"\"Get current system health snapshot.\"\"\"\n    try:\n        monitor = get_monitor()\n        return await monitor.get_health_summary()\n    except Exception as e:\n        logger.error(f\"Error getting health: {e}\")\n        raise HTTPException(500, str(e))\n\n\n@router.get(\"/requests\")\nasync def get_requests(status: str = \"all\", limit: int = 50):\n    \"\"\"Get active and completed requests.\n\n    Args:\n        status: Filter by 'active', 'completed', 'success', 'error', or 'all'\n        limit: Max number of completed requests to return (default 50)\n    \"\"\"\n    # Input validation\n    if status not in [\"all\", \"active\", \"completed\", \"success\", \"error\"]:\n        raise HTTPException(400, f\"Invalid status: {status}. Must be one of: all, active, completed, success, error\")\n    if limit < 1 or limit > 1000:\n        raise HTTPException(400, f\"Invalid limit: {limit}. Must be between 1 and 1000\")\n\n    try:\n        monitor = get_monitor()","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/deploy/docker/monitor_routes.py#L5-L41","documentation":"GET /monitor/health wraps monitor.get_health_summary() in a broad except that logs the exception and re-raises HTTPException(500, str(e)). The visible message is whatever failed — most commonly RuntimeError('Monitor not initialized') from get_monitor(), but also Redis errors or bugs in the health summary itself.","triggerScenarios":"Calling /monitor/health before MonitorStats initialization (most common); Redis unreachable when the health summary queries counters; any unexpected exception inside get_health_summary().","commonSituations":"Container orchestration probes hitting the route during boot; degraded Redis making monitor internals throw; deployments where startup ordering between app init and route availability is not enforced.","solutions":["Check the server logs — logger.error(f'Error getting health: {e}') records the root cause just before the 500.","If the message is 'Monitor not initialized', wait for/retry after startup completes (see error 195).","For Redis errors, restore Redis connectivity; the monitor depends on it.","Point readiness probes at a route that does not depend on the monitor until startup is verified."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import monitor as monitor_module\n\ndef health_available() -> bool:\n    return monitor_module.monitor_stats is not None","typeGuard":null,"tryCatchPattern":"resp = client.get(\"/monitor/health\")\nif resp.status_code == 500:\n    detail = resp.json()[\"detail\"]\n    if detail == \"Monitor not initialized\":\n        wait_for_readiness_then_retry()  # boot race\n    else:\n        inspect_server_log_for(\"Error getting health\")","preventionTips":["Point readiness probes at a dependency-free endpoint; use /monitor/health only when initialized.","Correlate the 500 detail with the 'Error getting health' log line for root cause.","Verify Redis is reachable before app startup completes."],"tags":["http-500","monitoring","initialization","fastapi"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}