{"record":{"id":"c0db8eef998af7a4","repo":"xtekky/gpt4free","slug":"nodriver-is-already-in-use-please-try-again-later","errorCode":null,"errorMessage":"Nodriver is already in use, please try again later.","messagePattern":"Nodriver is already in use, please try again later\\.","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"error","filePath":"g4f/requests/__init__.py","lineNumber":322,"sourceCode":"        lock_file.parent.mkdir(exist_ok=True)\n        # Implement a short delay (milliseconds) to prevent race conditions.\n        await asyncio.sleep(0.1 * random.randint(0, 50))\n        if lock_file.exists():\n            opend_at = float(lock_file.read_text())\n            time_open = time.time() - opend_at\n            if timeout * 2 > time_open:\n                debug.log(\n                    f\"Nodriver: Browser is already in use since {time_open} secs.\"\n                )\n                debug.log(\"Lock file:\", lock_file)\n                for idx in range(timeout):\n                    if lock_file.exists():\n                        await asyncio.sleep(1)\n                    else:\n                        break\n                    if idx == timeout - 1:\n                        debug.log(\"Timeout reached, nodriver is still in use.\")\n                        raise TimeoutError(\n                            \"Nodriver is already in use, please try again later.\"\n                        )\n            else:\n                debug.log(\n                    f\"Nodriver: Browser was opened {time_open} secs ago, closing it.\"\n                )\n                await BrowserConfig.stop_browser()\n                lock_file.unlink(missing_ok=True)\n        lock_file.write_text(str(time.time()))\n        debug.log(f\"Open nodriver with user_dir: {user_data_dir}\")\n    try:\n        browser_args = kwargs.pop(\"browser_args\", None) or [\"--no-sandbox\"]\n\n        if BrowserConfig.port:\n            browser_executable_path = \"/bin/google-chrome\"\n        browser = await nodriver.start(\n            user_data_dir=user_data_dir,\n            browser_args=[*browser_args, f\"--proxy-server={proxy}\"]","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/xtekky/gpt4free/blob/973504e1770928ed5fb82f43da528f441ad9ddc3/g4f/requests/__init__.py#L304-L340","documentation":"Raised by get_nodriver() in g4f/requests/__init__.py when a per-user-data-dir lock file exists and did not disappear within the whole timeout window (it polls once per second for `timeout` seconds). g4f serializes nodriver access with a lock file because two Browser instances sharing the same user_data_dir corrupt the profile, so a stale or genuinely held lock eventually produces this TimeoutError.","triggerScenarios":"Two concurrent requests both call get_nodriver with the same user_data_dir while the first browser is still open longer than `timeout` seconds; or a previous run crashed without removing its lock file, leaving a stale lock whose timestamp is newer than timeout*2 seconds logic did not trigger cleanup.","commonSituations":"Running g4f in multiple worker processes (gunicorn/uvicorn workers) that all default to the same 'nodriver' profile dir; a hard kill (OOM, SIGKILL, power loss) leaving the lock file behind; long Cloudflare challenges keeping the browser open past the timeout.","solutions":["Retry later, as the message suggests — the other holder usually releases the browser when done.","Give each concurrent worker its own user_data_dir: get_nodriver(user_data_dir=f\"worker-{worker_id}\") so locks do not collide.","Delete the stale lock file (path is printed by the adjacent debug.log 'Lock file:' line, typically under the platformdirs user_config_dir 'g4f-nodriver') after confirming no browser is actually running.","Increase the timeout argument so legitimate long sessions do not trip it."],"exampleFix":"// before\nbrowser, stop = await get_nodriver()  # shared default dir -> lock contention\n\n// after\nbrowser, stop = await get_nodriver(user_data_dir=f\"worker-{os.getpid()}\", timeout=600)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    browser, stop = await get_nodriver(timeout=120)\nexcept TimeoutError:\n    # another holder has the profile; back off and retry, or use a separate dir\n    await asyncio.sleep(30)\n    browser, stop = await get_nodriver(user_data_dir=f\"retry-{time.time()}\")","preventionTips":["Give each process/worker its own user_data_dir so locks never contend.","Always use `async with get_nodriver(...) as ...` style cleanup so the lock is released even on errors.","On startup, sweep stale g4f-* profile lock files when no chrome process is running.","Size the timeout argument to your worst-case legitimate browser session length."],"tags":["concurrency","lock-file","nodriver","timeout","browser-automation"],"backgroundTag":null,"analyzedSha":"973504e1770928ed5fb82f43da528f441ad9ddc3","analyzedAt":"2026-08-14T23:45:32.408Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}