Skip to content

fix(dashboard): retry the Windows action spawn without breakaway on E… - #135693

Closed
Yicheng-Mark wants to merge 1 commit into
NousResearch:mainfrom
Yicheng-Mark:fix/win32-action-spawn-breakaway-fallback
Closed

Yicheng-Mark wants to merge 1 commit into
NousResearch:mainfrom
Yicheng-Mark:fix/win32-action-spawn-breakaway-fallback

Conversation

@Yicheng-Mark

Copy link
Copy Markdown

Symptom

POST /api/hermes/update — or the Desktop app's "Update backend" affordance against a remote Windows backend — fails with HTTP 500:

{"detail": "Failed to start update: [WinError 5] Access is denied."}

whenever the dashboard/gateway runs inside a Windows job object that does not grant JOB_OBJECT_LIMIT_BREAKAWAY_OK (Task Scheduler, certain service runners, sandboxed sessions). No update ever starts. As reported in #135179.

Cause

_spawn_hermes_action in hermes_cli/web_server_gateway.py spawned the action with windows_detach_flags() unconditionally, and those flags include CREATE_BREAKAWAY_FROM_JOB. In a job that forbids breakaway, Popen raises PermissionError (WinError 5), which the endpoint surfaced as the 500.

_subprocess_compat.windows_detach_flags documents the exact contract: "A job that forbids breakaway yields PermissionError from Popen — callers catch OSError and fall back to windows_detach_flags_without_breakaway." gateway.py, gateway_windows.py and main_desktop.py follow it; this spawn site was the one that didn't.

Fix

Catch OSError from the breakaway spawn and retry once with windows_detach_flags_without_breakaway(), mirroring gateway.py's respawn path. The POSIX branch (start_new_session) is unchanged.

Regression tests added:

  • a denied breakaway (PermissionError on the breakaway flags) retries with the without-breakaway flags and still records the action's process handle;
  • a permitted breakaway spawns exactly once, with the breakaway flags;
  • POSIX keeps start_new_session and passes no creationflags.

Fixes #135179

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds a functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass — ran the new test module against the patched file on Windows (3/3), stubbing only the module's collaborators; full suite runs in CI
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Windows 11

Documentation & Housekeeping

  • I've updated relevant documentation — N/A, spawn behavior only
  • I've updated cli-config.yaml.example — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md — N/A
  • I've considered cross-platform impact — both platform branches covered by tests
  • I've updated tool descriptions/schemas — N/A

…RROR_ACCESS_DENIED

_spawn_hermes_action passed CREATE_BREAKAWAY_FROM_JOB unconditionally on
win32. Inside a job object without JOB_OBJECT_LIMIT_BREAKAWAY_OK (Task
Scheduler, some service runners), Popen raises PermissionError and
POST /api/hermes/update dies with a 500 instead of starting the update.

The contract in _subprocess_compat.windows_detach_flags -- callers catch
OSError and fall back to windows_detach_flags_without_breakaway() -- was
followed by gateway.py, gateway_windows.py and main_desktop.py but not
here. Do the same two-step spawn (135179).
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard comp/dashboard Web dashboard / control panel UI (dashboard/, landing) platform/windows area/install-update Installer, updater, packaging, wheels, doctor sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows labels Oct 9, 2026
@alt-glitch

Copy link
Copy Markdown

This was generated by AI during triage.

This overlaps #129325 and #108720. #129325 is the narrower canonical dashboard repair; this PR retries all OSErrors, so it has a material behavioral delta and is related rather than a duplicate.

@Yicheng-Mark

Copy link
Copy Markdown
Author

Closing in favor of #129325 (by @ggmmlong, opened 9 days earlier), which fixes the same spawn site in hermes_cli/web_server_gateway.py.

Comparing the two diffs, theirs is also the better fix: it gates the fallback on winerror == 5, so unrelated spawn failures (missing exe, bad cwd) keep surfacing as a single clear error, while this PR retried on every OSError. Its tests also exercise the real windows_detach_flags() values rather than sentinel constants. Nothing here is left uncovered by #129325.

#135179 stays reproducible until that lands — the terminal hermes update workaround from #129325 applies meanwhile.

@alt-glitch alt-glitch added os/windows Native Windows behaviour or breakage: PowerShell install, Windows paths, cmd.exe, WSL-vs-native diff and removed platform/windows labels Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/install-update Installer, updater, packaging, wheels, doctor comp/cli CLI entry point, hermes_cli/, setup wizard comp/dashboard Web dashboard / control panel UI (dashboard/, landing) os/windows Native Windows behaviour or breakage: PowerShell install, Windows paths, cmd.exe, WSL-vs-native diff P2 Medium — degraded but workaround exists 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]: Windows: POST /api/hermes/update fails with 500 [WinError 5] Access is denied in job objects without breakaway

2 participants