can1357/oh-my-pi · error
ssh://: ${target.name} is a Windows host; ssh:// supports PO
Error message
ssh://: ${target.name} is a Windows host; ssh:// supports POSIX remotes only (head/cat/mv) — use `bash` with a remote SSH command for Windows hosts What it means
The ssh:// file-transfer path (head/cat/mv style operations) only works against POSIX remotes. ensurePosixRemote consults the cached/probed host info and throws this error when the remote is detected as Windows, directing you to use the bash tool with a remote SSH command instead.
Source
Thrown at packages/coding-agent/src/ssh/file-transfer.ts:32
const DEFAULT_TIMEOUT_MS = 30_000;
/**
* Ensure the ControlMaster connection and pick the verified POSIX shell to
* run transfer commands under. Returns the shell name so the caller can
* wrap its snippet in `<shell> -c '…'`; OpenSSH otherwise hands the command
* to the user's login shell, which on fish/csh/tcsh hosts can't parse our
* `if [ … ]; then …` constructs (#3719).
*
* Windows hosts are refused up front — `ssh://` runs `head`/`cat`/`mv`/`test`
* directly and cmd/powershell can't drive those. Everywhere else, we require
* a non-empty `transferShell` (set by `probeHostInfo` after `sh -lc` /
* `bash -lc` / `zsh -lc` round-trips a marker against the remote).
*/
async function ensurePosixRemote(target: SSHConnectionTarget): Promise<"sh" | "bash" | "zsh"> {
await ensureConnection(target);
const info = await ensureHostInfo(target);
if (info.os === "windows") {
throw new Error(
`ssh://: ${target.name} is a Windows host; ssh:// supports POSIX remotes only (head/cat/mv) — use \`bash\` with a remote SSH command for Windows hosts`,
);
}
if (!info.transferShell) {
throw new Error(
`ssh://: ${target.name} has no verified POSIX shell for ssh:// read/write — none of sh/bash/zsh round-tripped a capability probe (use \`bash\` with a remote SSH command for this host)`,
);
}
return info.transferShell;
}
export interface RemoteFileReadOptions {
/** Maximum bytes to materialize; the helper fetches one extra byte to detect truncation. */
maxBytes: number;
signal?: AbortSignal;
timeoutMs?: number;
}
View on GitHub (pinned to 9690622007)
Solutions
- Use the bash tool with an explicit remote SSH command (e.g. `ssh host type file`) for Windows hosts
- Install/use a POSIX environment on the remote (WSL, Git Bash, Cygwin) and target that properly if you need ssh:// semantics
- Verify the host OS probe result is correct; if the host is actually POSIX, re-probe/fix host info
Example fix
// before: ssh:// read on a Windows host await readRemoteFile(winTarget, "C:/logs/app.log"); // after: run a remote command instead await runSsh(winTarget, ["type", "C:\\logs\\app.log"]); // via bash tool remote command
Defensive patterns
Strategy: validation
Validate before calling
import * as fs from "node:fs/promises";
// detect Windows remotes up front via a cheap probe command
const probe = await $`ssh ${targetArg} ver`.quiet().nothrow();
if (probe.exitCode === 0 && /Microsoft Windows/i.test(probe.stderr.toString() + probe.stdout.toString())) {
throw new Error("remote is Windows: use bash tool with remote ssh command, not ssh://");
} Try / catch
try {
await readRemoteFile(target, path);
} catch (err) {
if (err instanceof Error && err.message.includes("is a Windows host")) {
// route this target through remote SSH commands instead of ssh://
return runRemoteCommand(target, `type ${path}`);
}
throw err;
} Prevention
- Maintain a list of Windows hosts and exclude them from ssh:// workflows
- Use the bash tool with explicit remote commands for Windows targets
- Confirm host OS classification if you believe it was misdetected
When it happens
Trigger: Performing ssh:// read/write (upload/download/head/cat/mv/write) against a target whose probed host OS is "windows" — e.g. Windows OpenSSH server where `bash -lc`/`zsh -lc` marker round-trip fails but cmd/powershell responds.
Common situations: Pointing ssh:// tools at a Windows Server with OpenSSH installed, mixed fleet where one host is Windows, mis-probed OS due to a POSIX shell shim on Windows (rare).
Related errors
- symlinks not supported on this platform
- can't determine symlink type, since it is dangling
- GetFinalPathNameByHandleW failed with code {0}
- truncated u16
- truncated NtQueryDirectoryFile record
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e6691cafeaa9b935.
Report an issue: GitHub.