{"record":{"id":"cdfd0b4bdbac6905","repo":"odysseus-dev/odysseus","slug":"failed-to-retrieve-logs-str-e","errorCode":null,"errorMessage":"Failed to retrieve logs: {str(e)}","messagePattern":"Failed to retrieve logs: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"routes/diagnostics_routes.py","lineNumber":54,"sourceCode":"        try:\n            log_file = os.path.join(DATA_DIR, \"logs\", \"app.log\")\n            if not os.path.exists(log_file):\n                return {\"status\": \"success\", \"logs\": []}\n\n            # Safe tail read of the log file (max 5MB via rotation)\n            with open(log_file, \"r\", encoding=\"utf-8\", errors=\"ignore\") as f:\n                lines = f.readlines()\n\n            tail_lines = lines[-limit:] if len(lines) > limit else lines\n            tail_lines = [line.rstrip('\\r\\n') for line in tail_lines]\n\n            return {\n                \"status\": \"success\",\n                \"logs\": tail_lines\n            }\n        except Exception as e:\n            logger.error(f\"Diagnostics logs retrieval error: {e}\")\n            raise HTTPException(500, f\"Failed to retrieve logs: {str(e)}\")\n\n    @router.get(\"/api/db/stats\")\n    async def get_database_stats(request: Request) -> Dict[str, Any]:\n        require_admin(request)\n        try:\n            from core.database import get_detailed_stats\n            return get_detailed_stats()\n        except Exception as e:\n            logger.error(f\"DB stats error: {e}\")\n            raise HTTPException(500, \"Failed to retrieve database statistics\")\n\n    @router.get(\"/api/rag/stats\")\n    async def get_rag_stats(request: Request) -> Dict[str, Any]:\n        require_admin(request)\n        if rag_available and rag_manager:\n            return rag_manager.get_stats()\n        return {\"error\": \"RAG system not available\"}\n","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/diagnostics_routes.py#L36-L72","documentation":"Raised (HTTP 500) by the diagnostics logs endpoint (admin-gated) when anything inside the log-tail try block throws — most commonly an OSError while opening/reading the log file (missing file, permission denied, path is a directory) but the blanket `except Exception` also captures decode surprises. The original exception is logged as 'Diagnostics logs retrieval error' before the 500 is raised, with str(e) surfaced to the caller.","triggerScenarios":"GET of the logs tail endpoint when log_file points at a path that does not exist (logging not yet initialized / rotated away), is unreadable under the server's user, or when a filesystem error (NFS stall, disk issue) interrupts the read of a large log being read fully into memory via readlines().","commonSituations":"Fresh install where the log file has not been created yet; server runs under a different user than the one owning the logs directory; log rotated mid-request; extremely large log file causing memory pressure.","solutions":["Check the server console for the logged 'Diagnostics logs retrieval error: ...' line — it contains the exact OSError reason.","Verify the log file exists and is readable by the server process user (ls -l + sudo -u <user> head <file>).","If the file was rotated/renamed, point the diagnostics config at the current log path or restart so logging recreates it.","For huge logs, tail the file (seek from end) instead of relying on readlines() over the whole file."],"exampleFix":"// before\nwith open(log_file, 'r', encoding='utf-8', errors='ignore') as f:\n    lines = f.readlines()\n\n// after (streaming tail, no full-file read)\nimport subprocess\ntail = subprocess.run(['tail', '-n', str(limit), log_file], capture_output=True, text=True)\ntail_lines = tail.stdout.splitlines()","handlingStrategy":"try-catch","validationCode":"# Pre-flight the log file is readable before requesting the tail\nimport os\nif not os.path.isfile(log_file) or not os.access(log_file, os.R_OK):\n    skip_diagnostics('log file missing or unreadable')","typeGuard":null,"tryCatchPattern":"try { const r = await get('/api/logs?limit=200'); } catch (e) { if (e.status === 500 && /Failed to retrieve logs/.test(e.message)) { showBanner('Log file unavailable on server — see server console'); return []; } throw e; }","preventionTips":["Ensure the server process owns or can read the logs directory.","Check the 'Diagnostics logs retrieval error' server log line for the root cause before changing anything."],"tags":["diagnostics","logs","filesystem","permissions","admin"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}