X Tutup
Skip to content

fix: add Windows-compatible process checks in tunnel.py#4292

Open
giulio-leone wants to merge 4 commits intobrowser-use:mainfrom
giulio-leone:fix/tunnel-windows-pid-check
Open

fix: add Windows-compatible process checks in tunnel.py#4292
giulio-leone wants to merge 4 commits intobrowser-use:mainfrom
giulio-leone:fix/tunnel-windows-pid-check

Conversation

@giulio-leone
Copy link
Contributor

@giulio-leone giulio-leone commented Mar 7, 2026

Summary

Fixes #3912

tunnel.py was the only remaining file using raw os.kill(pid, 0) for process existence checks, which fails on Windows with a SystemError. The same fix was already applied to utils.py and main.py (which use ctypes.windll.kernel32.OpenProcess on Windows) but was missed in tunnel.py.

Changes

_is_process_alive()

  • Added sys.platform == 'win32' check with ctypes.windll.kernel32.OpenProcess()
  • Matches the existing pattern in utils.py:_pid_exists() and main.py:_pid_exists()

_kill_process()

  • Added Windows branch using ctypes.windll.kernel32.TerminateProcess()
  • signal.SIGTERM and signal.SIGKILL are not supported on Windows

Root Cause

os.kill(pid, 0) is Unix-specific for process existence checks. On Windows, it raises SystemError instead of working as expected. This broke all tunnel-related CLI operations on Windows (start, stop, status).

Testing

  • Unix behavior is unchanged (same os.kill(pid, 0) path)
  • Windows path uses the same ctypes approach already proven in utils.py and main.py

Summary by cubic

Make tunnel process checks and kills work on Windows in tunnel.py. Fixes #3912 and restores tunnel start/stop/status on Windows.

  • Bug Fixes
    • is_process_alive: On Windows, use WinDLL(..., use_last_error=True).OpenProcess; treat ERROR_ACCESS_DENIED (5) as alive; Unix still uses os.kill(pid, 0).
    • kill_process: On Windows, use TerminateProcess, check the return code, then poll to verify the process exited; log the Win32 error on failure. Unix still sends SIGTERM, then SIGKILL.
    • stop_tunnel: Warn when process termination fails.

Written for commit 6e675df. Summary will update on new commits.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="browser_use/skill_cli/tunnel.py">

<violation number="1" location="browser_use/skill_cli/tunnel.py:168">
P2: Windows process liveness check misclassifies `OpenProcess` access-denied failures as dead, causing live tunnel metadata to be deleted.</violation>

<violation number="2" location="browser_use/skill_cli/tunnel.py:180">
P2: Windows kill path reports success without checking whether `TerminateProcess` actually succeeded, which can hide failed termination and orphan tunnel processes.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@giulio-leone giulio-leone force-pushed the fix/tunnel-windows-pid-check branch from 5da0de6 to d5fbdec Compare March 8, 2026 22:07
giulio-leone added 3 commits March 9, 2026 15:17
tunnel.py was the only remaining file using raw os.kill(pid, 0) for
process existence checks, which fails on Windows with a SystemError.

The same fix was already applied to utils.py and main.py but missed
in tunnel.py.

Changes:
- _is_process_alive(): Use ctypes.windll.kernel32.OpenProcess on
  Windows, matching the pattern in utils.py and main.py
- _kill_process(): Use ctypes.windll.kernel32.TerminateProcess on
  Windows instead of signal.SIGTERM/SIGKILL which are not supported

Fixes browser-use#3912
Address review feedback:
- _is_process_alive: check GetLastError() for ERROR_ACCESS_DENIED (5),
  which means the process exists but we lack permissions to open it.
  Previously this was misclassified as 'dead'.
- _kill_process: check TerminateProcess return value instead of
  unconditionally returning True, which could hide failed termination.
- Log warning when process termination fails in stop_tunnel
- Capture GetLastError immediately after OpenProcess
@giulio-leone giulio-leone force-pushed the fix/tunnel-windows-pid-check branch from d5fbdec to 66da712 Compare March 9, 2026 14:19
@giulio-leone
Copy link
Contributor Author

Friendly ping — CI is green, tests pass, rebased on latest. Ready for review whenever convenient. Happy to address any feedback. 🙏

…dows

- Switch from ctypes.windll.kernel32.GetLastError() to ctypes.WinDLL
  with use_last_error=True + ctypes.get_last_error() so the error code
  from OpenProcess is captured atomically rather than via a second Win32
  call that can return a stale value.
- After TerminateProcess succeeds, poll _is_process_alive to confirm the
  process has actually exited before returning True. TerminateProcess is
  asynchronous; returning True without verification can hide orphaned
  tunnel processes.
- Log a warning with the Win32 error code when TerminateProcess fails.
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.

browser-use Windows Issue - os.kill(pid, 0) - Fails on Windows

1 participant

X Tutup