{"record":{"id":"456b0d10eb84c128","repo":"NanmiCoder/MediaCrawler","slug":"not-a-file","errorCode":null,"errorMessage":"Not a file","messagePattern":"Not a file","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"api/routers/data.py","lineNumber":107,"sourceCode":"            except Exception:\n                continue\n\n    # Sort by modification time (newest first)\n    files.sort(key=lambda x: x[\"modified_at\"], reverse=True)\n\n    return {\"files\": files}\n\n\n@router.get(\"/files/{file_path:path}\")\nasync def get_file_content(file_path: str, preview: bool = True, limit: int = 100):\n    \"\"\"Get file content or preview\"\"\"\n    full_path = DATA_DIR / file_path\n\n    if not full_path.exists():\n        raise HTTPException(status_code=404, detail=\"File not found\")\n\n    if not full_path.is_file():\n        raise HTTPException(status_code=400, detail=\"Not a file\")\n\n    # Security check: ensure within DATA_DIR\n    try:\n        full_path.resolve().relative_to(DATA_DIR.resolve())\n    except ValueError:\n        raise HTTPException(status_code=403, detail=\"Access denied\")\n\n    if preview:\n        # Return preview data\n        try:\n            if full_path.suffix == \".json\":\n                with open(full_path, \"r\", encoding=\"utf-8\") as f:\n                    data = json.load(f)\n                    if isinstance(data, list):\n                        return {\"data\": data[:limit], \"total\": len(data)}\n                    return {\"data\": data, \"total\": 1}\n            elif full_path.suffix == \".csv\":\n                import csv","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/NanmiCoder/MediaCrawler/blob/d6f7c5bb906b6dac40ddf343ef9e26438a3de092/api/routers/data.py#L89-L125","documentation":"A precondition check in _create_browser_context: it refuses to build a Playwright BrowserContext when self.browser is None, i.e. _connect_via_cdp never ran or failed before a context was requested. It is a guard exception, not an external failure — the caller tried to use the manager before a successful CDP connection was established.","triggerScenarios":"Calling _create_browser_context before _connect_via_cdp succeeds; after a previous connection dropped and self.browser was reset to None; an earlier connect_over_cdp exception was swallowed upstream so the manager is in an uninitialized state.","commonSituations":"Startup race: the crawler requests a page while Chrome/DevTools is still booting; a prior run's cleanup set browser=None and code reused the manager instance; exception handlers that log-and-continue past a failed connect then proceed to context creation.","solutions":["Ensure the connect step runs to completion before any context/page request — call _connect_via_cdp and only proceed on success","Check the manager state before use: `if not cdp_manager.browser: await cdp_manager.connect(...)`","If the connection may drop mid-session, wrap connect+context creation so a failed connect retries from launching the browser, not just context creation","Hunt upstream for swallowed exceptions that let execution reach this guard with browser=None"],"exampleFix":"// before\nbrowser_context = await self._create_browser_context(proxy, user_agent)\n\n// after\nif not self.browser:\n    raise RuntimeError(\"Browser not connected\")\nbrowser_context = await self._create_browser_context(proxy, user_agent)","handlingStrategy":"validation","validationCode":"async def ensure_connected(manager, playwright) -> None:\n    if not getattr(manager, \"browser\", None) or not manager.browser.is_connected():\n        await manager._connect_via_cdp(playwright)\n    assert manager.browser and manager.browser.is_connected(), \"connect step did not yield a live browser\"\n# call ensure_connected(manager, playwright) BEFORE _create_browser_context","typeGuard":"def manager_ready(manager) -> bool:\n    browser = getattr(manager, \"browser\", None)\n    return browser is not None and browser.is_connected()","tryCatchPattern":"try:\n    ctx = await manager._create_browser_context(proxy, ua)\nexcept RuntimeError as e:\n    if \"Browser not connected\" in str(e):\n        await manager.start()  # full reconnect, then retry once\n        ctx = await manager._create_browser_context(proxy, ua)\n    else:\n        raise","preventionTips":["Treat this guard as a bug in the caller: fix the call ordering, do not catch it routinely","Never swallow exceptions from the connect step — they turn into this precondition error later","Reset the manager to a known state (browser=None) only together with full teardown so state cannot drift"],"tags":["cdp","playwright","precondition","state-management","browser"],"backgroundTag":null,"analyzedSha":"d6f7c5bb906b6dac40ddf343ef9e26438a3de092","analyzedAt":"2026-08-15T01:39:07.505Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}