#4309·herdr

Windows host: machine add always fails 'not ready for saved machines' because detached_server_daemon requires not-in-job, and every process is in a job on Windows 11 26200

Author: Abdo-El-MobayadCreated Sep 17, 2026Updated Sep 17, 2026
Labelsbugwindowsmaintainer-neededp2remote

Is this a reproducible bug?

  • I confirm this is a reproducible bug, not a feature request, idea, question, contribution proposal, or direction check.
  • I reproduced this bug on the version and environment reported below using the exact steps provided.

Current behavior

Against a Windows host, herdr machine add <host> --label X always ends with error: remote server is not ready for saved machines; machine was not saved, even after accepting the offered server restart, and every repeat produces the same result.

The saved-machine readiness gate needs the host server to report detached_server_daemon: true. On Windows that flag is derived from IsProcessInJob(hProcess, NULL) == FALSE (plus no console window). On Windows 11 build 26200 every process I can find is inside a job object, including explorer.exe, WindowsTerminal.exe, WmiPrvSE.exe, and every herdr server however it was launched, so the flag can never become true and the gate can never pass.

Related: #4205 and #3521 describe the same prompt appearing while restart_needed is false, on macOS. This report is the Windows side, where the flag is structurally unreachable and the consequence is that saved machines cannot be created at all.

What the client prints:

remote herdr server on <host> (session default) is currently running:
  server: v0.9.1
  prepared binary: 0.9.1

the remote server was started by a herdr build that may not survive SSH connection loss. restart it so network drops disconnect only this client.
This stops active remote pane processes, including shells, agents, dev servers, and tests.
restart the remote server now? [y/N] y
stopped the remote herdr server on <host>; it will restart when the remote client bridge attaches.
error: remote server is not ready for saved machines; machine was not saved

herdr status server --json on the host, for the server the bridge relaunched (WMI Win32_Process.Create with DETACHED_PROCESS, no conhost.exe child, session 0), and identically for a server started from the Windows Terminal TUI:

json
{"status":"running","running":true,"version":"0.9.1","protocol":22,"capabilities":{"live_handoff":false,"detached_server_daemon":false,"endpoint_protocol_generation":1,"surface_interest":true,"health_check":true},"compatible":true,"endpoint_compatible":true,"socket":"C:\\Users\\<user>\\AppData\\Roaming\\herdr\\herdr.sock","session":null,"restart_needed":false,"server_binary_stale":false}

IsProcessInJob(hProcess, NULL) through a small P/Invoke, on two different Windows 11 26200 machines:

WmiPrvSE.exe                      sid=0  inJob=True
explorer.exe                      sid=1  inJob=True
WindowsTerminal.exe               sid=1  inJob=True
herdr.exe server (WMI relaunch)   sid=0  inJob=True  conhost children=0
herdr.exe server (TUI launched)   sid=1  inJob=True

Where this appears to come from in the v0.9.1 source:

  • src/platform/windows.rs, current_process_is_detached_server_daemon(): true only if GetConsoleWindow() is null and current_process_is_in_job() is Ok(false).
  • src/remote/restart_policy.rs, remote_server_restart_reason(): !detached_server_daemon yields DaemonDetach.
  • src/remote/attach.rs, prepare_saved_ssh(): after the restart, any remaining restart reason maps to "remote server is not ready for saved machines".

The WMI relaunch correctly escapes the SSH session's kill-on-close job and uses DETACHED_PROCESS, but it still lands inside a job, so the freshly launched server reports false and the gate rejects it again.

Side effect worth knowing: for an Administrators-group account, Windows OpenSSH sessions carry the full high-integrity token (whoami /groups shows High Mandatory Level). The WMI relaunch from that session therefore produces a session-0, high-integrity server, and a normal herdr at the host's own keyboard then fails with access is denied (os error 5) until herdr server stop is run over SSH and the server is started again at the keyboard.

Expected behavior

Either machine add succeeds against a Windows host whose server was launched by herdr's own detached path, or the restart is not offered when it cannot change the outcome. Deriving the detached flag from current_job_kills_processes_on_close() (already used for the launch decision) rather than bare IsProcessInJob would match the intent on Windows.

Reproduction

  1. Host (Windows 11 26200, OpenSSH Server, key auth, DefaultShell cmd.exe): start herdr from Windows Terminal so the default session is running.
  2. Client (Windows 11 26200), in Command Prompt: herdr machine add <host> --label "Desktop".
  3. Answer y at the restart prompt. Observe stopped the remote herdr server ... followed by error: remote server is not ready for saved machines; machine was not saved.
  4. herdr machine list on the client prints No saved SSH machines.
  5. Repeat step 2: identical outcome. On the host, herdr status server --json shows "detached_server_daemon":false for the relaunched server.

herdr --remote <host> with N at the same prompt attaches and works normally in both directions between the two machines.

Impact

Saved machines cannot be used with a Windows host at all. Each accepted restart kills every pane process on the host, and the first time it also left the host's session unusable from its own keyboard (session-0, high-integrity server) until a manual stop.

Environment

  • Herdr version: 0.9.1 stable on both machines, installed through install.ps1
  • Update channel (stable or preview): stable
  • Operating system: Windows 11 Pro 10.0.26200 on both client and host
  • Terminal: Windows Terminal 1.24 and plain Command Prompt on the client (same result)
  • Shell, if relevant: PowerShell 7.6.6 MSI as the pane shell; host DefaultShell cmd.exe (also reproduced with powershell.exe)
  • Relevant config, if any: default [remote] settings; default session, no named HERDR_SESSION; SSH key auth; Tailscale MagicDNS names