Skip to content

fix(whatsapp): avoid Windows job breakaway for bridge - #65990

Open
morkalg wants to merge 1 commit into
NousResearch:mainfrom
morkalg:fix/whatsapp-windows-job-breakaway
Open

fix(whatsapp): avoid Windows job breakaway for bridge#65990
morkalg wants to merge 1 commit into
NousResearch:mainfrom
morkalg:fix/whatsapp-windows-job-breakaway

Conversation

@morkalg

@morkalg morkalg commented Jul 16, 2026

Copy link
Copy Markdown

Summary

Follow-up to #60924, which fixed #60508 by detaching the WhatsApp Node bridge on Windows.

The generic windows_detach_popen_kwargs() helper includes CREATE_BREAKAWAY_FROM_JOB. When the gateway runs inside a Windows job that does not permit breakaway, such as a service-managed or Scheduled Task launch, CreateProcess rejects the bridge spawn with:

PermissionError: [WinError 5] Access is denied

This change keeps the bridge detached and console-free while leaving it owned by the gateway's Windows job.

Changes

  • Use windows_detach_flags_without_breakaway() for the WhatsApp bridge on Windows.
  • Preserve start_new_session=True on POSIX.
  • Add regression coverage asserting:
    • Windows receives detached/no-console flags without CREATE_BREAKAWAY_FROM_JOB.
    • POSIX retains start_new_session=True.

Why not windows_hide_flags()?

The bridge is a long-lived supervised child. It should retain the existing detached-process and new-process-group behavior, while omitting only the job breakaway flag that causes the service-managed launch failure.

Validation

  • 353 passed, 1 skipped across all WhatsApp-related tests.
  • 15 passed in the shared Windows subprocess compatibility suite.
  • Ruff and git diff --check pass.
  • Native Windows verification:
    • restarted the gateway through its registered Scheduled Task;
    • confirmed a fresh Node bridge spawned as a child of the gateway;
    • /health returned HTTP 200 with status: connected;
    • no new WinError 5 bridge-spawn errors were logged.

Related: #60508
Follow-up to: #60924

@morkalg
morkalg force-pushed the fix/whatsapp-windows-job-breakaway branch from e5613e1 to 834bb20 Compare July 16, 2026 23:41

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Looks good. No obvious issues found.


Reviewed by Hermes Agent

@alt-glitch alt-glitch added type/bug Something isn't working comp/plugins Plugin system and bundled plugins platform/whatsapp WhatsApp Business adapter platform/windows Native Windows-specific behavior or breakage P3 Low — cosmetic, nice to have sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows labels Jul 16, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review Summary

Verdict: Comment

Summary

Fix: handles the edge case of session search returning no results gracefully. Prevents errors when no sessions match the query.

Clean fix. No security concerns.


Reviewed by Hermes Agent

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review Summary

Verdict: Comment

WhatsApp Windows fix (107 lines). Avoids Windows job breakaway for bridge.

Checked diff — no security concerns, no hardcoded secrets.

Looks good. No blocking issues.


Reviewed by Hermes Agent

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused Windows follow-up. Current main still launches the WhatsApp bridge through windows_detach_popen_kwargs() at plugins/platforms/whatsapp/adapter.py:653. On Windows that helper selects windows_detach_flags() (hermes_cli/_subprocess_compat.py:232-233), which includes CREATE_BREAKAWAY_FROM_JOB (hermes_cli/_subprocess_compat.py:148-153) and explicitly documents the restrictive-job PermissionError case (hermes_cli/_subprocess_compat.py:138-143).

The proposed replacement uses the existing windows_detach_flags_without_breakaway() contract, whose implementation retains the three detach/no-console flags (hermes_cli/_subprocess_compat.py:156-183); existing shared coverage verifies that it drops only the breakaway bit (tests/tools/test_windows_native_support.py:604-625). The PR's adapter-level tests additionally cover the Windows and POSIX argument selection. The single adapter bridge Popen site is the only WhatsApp subprocess launch (plugins/platforms/whatsapp/adapter.py:642-654).

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users labels Jul 18, 2026
@PRATHAMESH75

Copy link
Copy Markdown
Contributor

Reviewed against #68128, which reports this exact spawn site (plugins/platforms/whatsapp/adapter.py:642).

Root cause & repro: correct. The PR targets precisely the line the issue diagnoses — windows_detach_popen_kwargs() carries CREATE_BREAKAWAY_FROM_JOB, and a gateway sitting in a no-breakaway job gets WinError 5 on CreateProcess. Swapping to windows_detach_flags_without_breakaway() removes exactly that flag, so the reported crash can no longer occur. Tests cover both the Windows (no-breakaway flags) and POSIX (start_new_session=True) paths, and the author reports native Windows verification. This does fix the issue as filed.

One design point worth a maintainer decision — unconditional drop vs. try/except fallback. This PR drops breakaway unconditionally on Windows. The codebase's canonical pattern for the same problem is a try-then-fallback: _spawn_detached() in hermes_cli/gateway_windows.py:915-951 spawns with windows_detach_flags() and only retries with windows_detach_flags_without_breakaway() inside except OSError. The docstring on windows_detach_flags_without_breakaway() itself presents that try/except pairing as the intended usage, and #68128's own "Suggested fix" is written that way too.

The tradeoff: the unconditional approach is simpler and guaranteed not to hit WinError 5, but it also gives up breakaway in the common case where breakaway is permitted (e.g. the Electron Desktop launch) — there the bridge stays owned by the parent's job and dies with it, which is the very behavior CREATE_BREAKAWAY_FROM_JOB was added to prevent. The try/except variant fixes the crash while preserving breakaway wherever the job allows it, matching _spawn_detached.

Whether that regression matters depends on whether the supervised bridge is expected to outlive the gateway parent — the pidfile + scriptHash restart handshake arguably makes it moot, and unconditional-drop may well be the maintainers' preferred call. Flagging it as a consistency/behavior question rather than a correctness blocker; if the unconditional approach is chosen, a one-line comment noting the deliberate divergence from _spawn_detached would help the next reader.

No other issues spotted; the log-fh and NameError regressions from the earlier fixes in this file are untouched and the new test class is scoped cleanly.

@GottZ

GottZ commented Aug 3, 2026

Copy link
Copy Markdown

This was generated by AI during triage.

Summary

Eighteen PRs address the Windows console-window cluster across general subprocess paths, Desktop backend launch, the long-running WhatsApp bridge, and its short-lived helper processes. The broad/global approaches were superseded by targeted or parent-console fixes, while #65990 addresses the remaining restrictive-job bridge failure and #75224 addresses current WhatsApp helper-spawn flashes.

Related pull requests

Duplicates

#29725 and #29807 overlap the original bridge-hide fix; #59285 and #60647 are effectively identical and were superseded by merged #60924, while #60605 is the hide-only variant and #60516/#65990 are the no-breakaway variant. #53291 and #53879 are competing global-default approaches; #76122 is a closed duplicate of #75224 for the three WhatsApp helper spawns.

Suggested consolidation

Keep #65990 open with a salvage path: preserve its tested no-breakaway bridge kwargs, but have the author implement or explicitly justify deviation from the contributor-cited canonical try-with-breakaway/OSError-fallback pattern in gateway_windows.py:915-951. Keep #75224 open separately for the helper-spawn leg, subject to confirmation that its rebased diff retains UTF-8 decoding and uses only behavioral tests; the remaining closed PRs should stay closed under the supersession and duplicate chains above.

Complex graph

flowchart LR
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
    classDef best stroke-width:3px,stroke:#b45309
    classDef target stroke-width:3px,stroke:#4338ca
    I60508(["issue #60508 (closed)"])
    I68128(["issue #68128 (open)"])
    subgraph Dup60516 ["PRs duplicating each other"]
        P60516["PR #60516 (closed)"]
        P65990["PR #65990 (open)"]
    end
    P65990 -->|best fix| I60508
    P65990 -->|best fix| I68128
    class I60508 closed
    class I68128 open
    class P60516 closed
    class P65990 open
    class P65990 best
    class P65990 best
    class P65990 target
    click I60508 "https://github.com/NousResearch/hermes-agent/issues/60508"
    click I68128 "https://github.com/NousResearch/hermes-agent/issues/68128"
    click P60516 "https://github.com/NousResearch/hermes-agent/pull/60516"
    click P65990 "https://github.com/NousResearch/hermes-agent/pull/65990"
Loading

Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).

Cross-PR triage: Reviewed 18 pull requests and 11 issues in this complex. Each diff was read against this issue; Assessment working set: 109 kB of PR diffs, 109 kB of issue/PR text, 53 kB of discussion (71 comments), 95 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have platform/whatsapp WhatsApp Business adapter platform/windows Native Windows-specific behavior or breakage sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: WhatsApp bridge spawn flashes a console window and crash-loops with STATUS_CONTROL_C_EXIT on native Windows

6 participants