Skip to content

fix(launch): a profile open in the user's own Chrome is exit 11, not UnexpectedError (#984) - #1058

Merged
ffroliva merged 2 commits into
developfrom
bugfix/984-profile-in-use
Oct 23, 2026
Merged

ffroliva merged 2 commits into
developfrom
bugfix/984-profile-in-use

Conversation

@ffroliva

@ffroliva ffroliva commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Reproduced on develop (2026-10-23, Windows, Chrome 141, ci-probe with a plain chrome.exe --user-data-dir=<profile> holding it). gflow credits user --json exited 1, UnexpectedError. The launch error is a generic Playwright Error: "Opening in existing browser session. This usually means that the profile is already in use by another instance of Chromium." That matches none of _TARGET_CLOSED_MARKERS, so Error-path browser teardown leaves Chrome holding the profile dir (TargetClosedError on the next run) #293's stale-Chrome classifier never fired.
  • New browser_manager.profile_in_use_error(exc, profile_dir) returns a ProfileLockedError (exit 11, MCP profile-locked, not retryable) whose hint says to close that Chrome window or use another --profile. FlowApiClient._launch_persistent_context calls it, which covers credits, every generation command and their MCP twins.
  • Ordering matters: Chrome uses the same "already in use" header for a read-only profile ("Lock file can not be created: Access is denied"),, a case already measured in several Windows languages. So the new check runs after _is_profile_access_denied. My first version put it before, and the existing test_process_singleton_access_denied_raises_profile_access_error matrix (10 cases) went red. Fixed, with a dedicated regression test.
  • auth renew is not changed. Its headless launch fails as TargetClosedError, and the feat(credits): add --refresh to renew expired sessions; add gflow auth renew #982 per-profile "Close any Chrome window using this profile" skip already handles that (measured on the same held profile).

Closes #984

Test plan

  • TDD: tests/api/test_profile_in_use.py. The helper classifies the measured message, ignores other launch errors, the client raises ProfileLockedError, and a read-only profile stays ProfileAccessError.
  • /gflow:check gates: hygiene, links, PII, website mirror, council memory, ruff, format, pyright, offline suite 5406 passed (the first run's 10 failures were the ordering regression above).
  • Live, ci-probe held by my own Chrome (PID recorded, stopped by PID afterwards; no process left on the profile):
  • Control with the profile free: credits user gives the same result on this branch and on untouched develop (ci-probe lands on Flow's /about, an account state, exit 31).
  • The live run used the pre-reorder build. The reorder only matters when "Lock file can not be created" is present, and the live message has no such line.

Summary by CodeRabbit

  • Bug Fixes
    • Chrome launch errors caused by a profile being used by another instance are now reported as a profile lock instead of an unexpected error. The command exits with code 11, and MCP reports profile-locked.
    • Error guidance now recommends closing the other Chrome window or choosing a different profile. Read-only profile access errors continue to be reported as access errors.

…UnexpectedError (#984)

Chrome refuses the launch with 'profile is already in use by another
instance'; it matched no #293 marker and escaped as error_unhandled. The new
browser_manager.profile_in_use_error raises ProfileLockedError, checked after
the read-only (ProfileAccessError) check, which shares that header.

Closes #984
@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 23 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 45540f02-2ea1-4c57-bbb2-30b93c3c514f
📥 Commits

Reviewing files that changed from the base of the PR and between 7c5625c and 21a12b0.

📒 Files selected for processing: 2
  • src/gflow_cli/api/client.py
  • tests/api/test_profile_in_use.py

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: cc968763-7da9-4108-8058-d9fffef84c3f
📥 Commits

Reviewing files that changed from the base of the PR and between 6d924d0 and 7c5625c.

📒 Files selected for processing: 4
  • CHANGELOG.md
  • src/gflow_cli/api/client.py
  • src/gflow_cli/browser_manager.py
  • tests/api/test_profile_in_use.py

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.

📝 Walkthrough

When Chrome reports that a profile is already in use by another instance, the launch path now raises ProfileLockedError. The error includes the profile path and guidance to close the other Chrome window or use another profile. Tests cover classification and the API client launch path.

Changes: Profile lock classification

Layer / File(s) Summary
Classify profile-in-use launch errors
src/gflow_cli/browser_manager.py, tests/api/test_profile_in_use.py
profile_in_use_error recognizes the profile-in-use message and returns ProfileLockedError. Tests cover matching and unrelated launch errors.
Raise the classified error during launch
src/gflow_cli/api/client.py, tests/api/test_profile_in_use.py, CHANGELOG.md
_launch_persistent_context raises the classified error after checking for profile-access denial. Tests cover both error paths. The changelog records the error mapping and remediation guidance.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: kittinan

Merge Risk: ⚪ Minimal · up to 7c562

A profile already open in Chrome receives the intended actionable error. No issue identified here needs resolution before merge.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 3 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly identifies the main change: classify profiles already open in the user's Chrome as exit 11 instead of UnexpectedError.
Linked Issues check Passed Issue #984 requires a typed, actionable error when Chrome already holds the profile, preferably exit 11. The PR adds profile_in_use_error, maps the measured Playwright message to `ProfileLockedError…
Out of Scope Changes check Passed The changed source implements the shared launch-error mapping required by #984. The tests verify that behavior and protect the existing access-denied behavior. The changelog documents the same fix. No…
Full details: Linked Issues check

Explanation

Issue #984 requires a typed, actionable error when Chrome already holds the profile, preferably exit 11. The PR adds profile_in_use_error, maps the measured Playwright message to ProfileLockedError, and invokes it from FlowApiClient._launch_persistent_context after the access-denied check. The reported result is exit 11 with MCP profile-locked and retryable: false. The added tests cover classification, client propagation, unrelated errors, and the read-only profile regression.

Full details: Out of Scope Changes check

Explanation

The changed source implements the shared launch-error mapping required by #984. The tests verify that behavior and protect the existing access-denied behavior. The changelog documents the same fix. No unrelated change is identified in the supplied PR evidence.

Full details: Docstring Coverage

Explanation

Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 3 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…uncil)

The #293 TargetClosedError shares the header; it keeps its incident capture and
its crashed-for-another-reason hint. Other launch sites -> #1059.
@ffroliva

Copy link
Copy Markdown
Owner Author

Council review: YELLOW.

Re-run live with ci-probe held by my own Chrome: still exit 11 (ProfileLockedError). That Chrome was stopped by PID and nothing is left on the profile. Suite: 5407 passed.

@ffroliva
ffroliva merged commit 3b717d0 into develop Oct 23, 2026
17 checks passed
@ffroliva
ffroliva deleted the bugfix/984-profile-in-use branch October 23, 2026 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

credits user: UnexpectedError when the profile is open in the user's own Chrome

1 participant