{"record":{"id":"38afd31021f248f2","repo":"unclecode/crawl4ai","slug":"monitor-not-initialized","errorCode":null,"errorMessage":"Monitor not initialized","messagePattern":"Monitor not initialized","errorType":"exception","errorClass":"RuntimeError","httpStatus":500,"severity":"error","filePath":"deploy/docker/monitor.py","lineNumber":390,"sourceCode":"            \"timestamps\": [int(d[\"time\"]) for d in data],\n            \"values\": [d.get(\"value\", d.get(\"browsers\")) for d in data]\n        }\n\n    def get_janitor_log(self, limit: int = 100) -> List[Dict]:\n        \"\"\"Get recent janitor events.\"\"\"\n        return list(self.janitor_events)[-limit:]\n\n    def get_errors_log(self, limit: int = 100) -> List[Dict]:\n        \"\"\"Get recent errors.\"\"\"\n        return list(self.errors)[-limit:]\n\n# Global instance (initialized in server.py)\nmonitor_stats: Optional[MonitorStats] = None\n\ndef get_monitor() -> MonitorStats:\n    \"\"\"Get global monitor instance.\"\"\"\n    if monitor_stats is None:\n        raise RuntimeError(\"Monitor not initialized\")\n    return monitor_stats\n","sourceCodeStart":372,"sourceCodeEnd":392,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/deploy/docker/monitor.py#L372-L392","documentation":"get_monitor() in deploy/docker/monitor.py returns the module-global monitor_stats, set once in server.py's startup path (monitor_module.monitor_stats = MonitorStats(redis)). If it is still None — startup incomplete, bypassed, or the module used standalone — it raises RuntimeError('Monitor not initialized'). Any /monitor/* route then converts this into a 500.","triggerScenarios":"Hitting /monitor/health (or any monitor route) before the server's startup/lifespan hook that constructs MonitorStats with Redis has run; importing monitor_routes in a test or secondary app where server.py's initialization never executes; initialization aborted because the Redis connection failed.","commonSituations":"Health checks that fire immediately at container boot, racing app startup; unit tests mounting only the router; a Redis outage during startup leaving monitor_stats unset while the app still serves traffic.","solutions":["Ensure the app is started through the normal server.py entry point so MonitorStats is created during startup.","Retry the monitor request after startup completes (readiness probe vs liveness probe).","If it persists, check startup logs for a Redis connection failure that skipped monitor initialization.","In tests, set monitor_stats manually: monitor_module.monitor_stats = MonitorStats(fake_redis)."],"exampleFix":"# before (test mounts router directly)\napp.include_router(monitor_router)  # /monitor/health -> 500 'Monitor not initialized'\n\n# after\nimport monitor as monitor_module\nmonitor_module.monitor_stats = MonitorStats(fake_redis)\napp.include_router(monitor_router)","handlingStrategy":"try-catch","validationCode":"import monitor as monitor_module\n\ndef monitor_ready() -> bool:\n    return monitor_module.monitor_stats is not None","typeGuard":"def is_monitor_initialized() -> bool:\n    from monitor import monitor_stats\n    return monitor_stats is not None","tryCatchPattern":"from monitor import get_monitor\n\ntry:\n    m = get_monitor()\nexcept RuntimeError:\n    m = None  # startup incomplete; skip monitor features or retry after readiness","preventionTips":["Gate /monitor scraping on a readiness signal, not process start.","In tests, assign monitor_stats explicitly before exercising routes.","Ensure MonitorStats(redis) runs in the app's startup hook unconditionally, with Redis failures made loud."],"tags":["initialization","runtime-error","fastapi","monitoring"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}