Your Browser Automation Started Hanging After an Update? Blame the Keychain
If you run browser automation on a Mac or Linux box, you may have hit this one recently: your script worked fine for months, then after a library update the headless browser just... never starts. No error, no crash, just a hang and a timeout 30 seconds later. Or worse: on a desktop, a macOS Keychain password dialog pops up every time a fresh browser profile launches, asking for a password your script doesn't know.
I hit this exact thing with browser-use, and it took a while to track down, because nothing about the failure looks like what it is. This is what's happening and how to fix it.
What you see
Symptoms vary by platform, but the shape is the same:
-
Headless / CI:
BrowserSession.start()hangs. The Chromium process starts, but the CDP debug port never opens. The watchdog eventually gives up with something likeTIMEOUT ERROR - Handling took more than 30.0sorBrowser did not start within 30 seconds. - Interactive desktop (macOS): a Keychain password prompt pops on every launch of a fresh browser profile. Say no or let it sit, and you get the hang.
- Linux with a keyring daemon: same hang when gnome-keyring or kwallet is registered.
It's fully deterministic. One minute the browser starts in a second, the next it blocks forever.
What's actually happening
The root cause is in the browser automation library's default Chrome arguments. browser-use used to launch Chromium with two flags:
--use-mock-keychain
--password-store=basic
These tell Chromium to skip the OS credential store entirely. Browser automation doesn't need to decrypt your saved passwords; a fresh temporary profile has nothing in the keychain anyway.
Then a PR (browser-use#3225, "fix-auth") removed both flags. The intent was reasonable: if you point the tool at a real user Chrome profile, Chromium needs keychain access to decrypt saved passwords and cookies. But the flags were removed globally, not just for real profiles. So now browser-use-managed profiles (temp dirs, the default profile dir) also touch the OS credential store.
And here's the kicker: Chromium's profile init synchronously calls into the credential store on startup. On a headless box with no interactive session to answer, that call blocks forever instead of failing fast. The browser never finishes starting, so the CDP port never opens, and the 30-second watchdog does its thing.
You can verify it yourself. Run Chromium with the flags:
"$CHROME_BIN" --headless=new --use-mock-keychain --password-store=basic \
--user-data-dir=$(mktemp -d) --remote-debugging-port=9334
CDP responds in about a second. Drop the flags and the same command just sits there.
The fix
The proper fix (re-adding the flags for managed profiles only) is still in review upstream as of this writing — three PRs have been proposed and none merged. So for now, the workaround is on your side.
Option 1: pass the flags yourself. With browser-use, BrowserProfile accepts extra args:
from browser_use import BrowserProfile, Browser
profile = BrowserProfile(
headless=True,
args=["--use-mock-keychain", "--password-store=basic"],
)
browser = Browser(profile=profile)
Option 2: pin the version. The regression shipped in the flag-removal PR, so anything after that release is affected. If you don't need the newest features, pin to the last version before the change and move on.
Option 3: patch it locally. If you're stuck on a newer version, add the two flags back to CHROME_DEFAULT_ARGS in browser_use/browser/profile.py. It's two lines, and it'll survive until a proper fix lands.
The broader lesson
This one generalizes beyond browser-use. If an automation tool starts hanging or prompting after an update, and the process is alive but never becomes ready, check the launch arguments before you blame the network or the tool itself. Tools that add flags to make real-user features work can silently break the disposable-profile path — the default case for automation.
Also worth remembering: when a headless process blocks on a credential store, the failure signature is a hang, not an error. No log line tells you "I'm waiting for keychain access." The process is just stuck in a syscall, and only a launch-arg diff (or a thread dump showing the stuck call) reveals it.
If you're building tooling that wraps Chromium, keep the mock-keychain flags for managed profiles. Real user profiles need the keychain; disposable automation profiles never do, and mixing the two is how you get 30-second hangs in CI at 2am.
The issue is tracked here: browser-use/browser-use#5415. If you're hitting this, thumbs-up the issue and the fix PRs so it actually lands.
Top comments (1)
this is a great example of a regression that looks like a browser/CDP problem but is actually happening much earlier during Chromium startup.
The managed-profile vs real-user-profile distinction is the key point. --use-mock-keychain and --password-store=basic make sense for disposable automation profiles, while removing them globally creates a very different failure mode in headless environments.
I’ve run into similar issues where an update changes a default launch flag and suddenly CI starts timing out with almost no useful error. Comparing the actual Chromium command line before and after an upgrade is often much faster than debugging the automation layer itself.
The part about the process being alive but CDP never becoming available is especially useful. That’s a good diagnostic signal that startup is blocked rather than the browser simply crashing.
Curious if the upstream fix will eventually make the keychain behavior conditional on whether a persistent user profile is being used. That seems like the cleanest long-term solution.