Skip to content

shell: report a truncated -c command line instead of hanging on it - #4

Merged
ale-rinaldi merged 1 commit into
mainfrom
fix/windows-command-line-limit
Sep 5, 2026
Merged

shell: report a truncated -c command line instead of hanging on it#4
ale-rinaldi merged 1 commit into
mainfrom
fix/windows-command-line-limit

Conversation

@ale-rinaldi

@ale-rinaldi ale-rinaldi commented Sep 5, 2026

Copy link
Copy Markdown
Member

Fixes #3 (residual finding from #1).

Root cause

A remote shell caps how long a single command line may be, and past that cap it truncates the line and says nothing at all. Instrumenting the raw terminal stream over an over-long line shows __DWSH_BEGIN__ arriving and the prompt returning, with no error text — the command runs truncated, and what falls off the end is exactly the __DWSH_RC_..._END__ sentinel -c waits for. So -c burned its whole --timeout, or hung forever with the default of none.

It is not Windows-specific. cmd.exe cuts at 8190 characters, but a *nix remote truncates too, depending on the remote user's shell:

Remote shell Reads the prompt line Line limit
bash, zsh raw mode (line editing) ~1 MB, no practical limit
sh, dash, ash canonical mode 4094 characters (tty line discipline)
cmd.exe 8190 characters

Measured under dash on a live Linux agent: 4094 passes, 4095 does not.

The report guessed cmd.exe would print The input line is too long. and that it simply was not reaching the client. It prints nothing in this path — there is no remote error to surface, which is why the fix cannot be better output handling.

Change

Which shell the remote user has is not knowable in advance, and guessing it would be the wrong side of the trade: a wrong guess denies work the remote would have run. So detect rather than predict.

A short probe line is typed after the command. A shell reads it only once it has read and run the command line, so its marker cannot come back before that command's RC sentinel — unless the line was cut short and took the sentinel with it. Verified under dash and on Windows: with the line truncated the RC never appears and the probe still does.

Like the RC sentinel, the probe marker is assembled by the remote ($? / %errorlevel%), so neither the PTY echoing the typed line back nor a command printing its own stdin can be mistaken for it.

An earlier revision of this branch also pre-checked the length against cmd.exe's 8190. That was dropped: it baked into the client an assumption about the remote — the current agent hardcodes cmd.exe, with a powershell.exe line commented out right beneath it — and if that ever flips the check becomes a false rejection. The error message likewise names no character count, since every such figure belongs to one shell only.

Honest limit: detection cannot prevent the partial execution that already happened. It replaces a silent hang with a clear error.

$ dwshell some-host -c "<over-long command>"
dwshell: the remote shell truncated the command line, so it ran a partial
command and the exit-code marker was lost; send a shorter command, or upload
it with `dwshell put` and run it by path

Verification

Case Before After
Windows, wrapped line 8190 ok ok (3 s)
Windows, 8191 and 12000 hangs for the full --timeout reported in 2–3 s
dash, line past 4094 RC lost, hangs probe fires
Linux, exit code propagation ok ok
Linux, 1 MB bash command ok ok
Linux, 60 KB command byte-exact byte-exact
-c "head -1" (reads stdin) times out times out, no false positive

gofmt, go vet, go test -race ./... green.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MvidAFW9a2r4hTgHPW9ywG

A remote shell caps how long a single command line may be, and past that
cap it truncates the line and says nothing at all: the command still
runs, but what falls off the end is dwshell's RC sentinel, so -c waited
out its whole --timeout — or, with no --timeout, forever — for a marker
that could never arrive.

This is not specific to Windows. cmd.exe cuts at 8190 characters, but a
*nix remote truncates too, depending on the user's shell: bash and zsh
read the prompt line in raw mode and take a megabyte, while sh, dash and
ash read in canonical mode, where the tty line discipline cuts at 4094.
Measured under dash on a live agent: 4094 passes, 4095 does not.

Which shell the remote user has is not knowable in advance, and guessing
it would be the wrong side of the trade — a wrong guess denies work the
remote would have run. So detect instead of predict: type a short probe
line after the command. A shell reads it only once it has read and run
the command line, so its marker cannot come back before that command's
RC sentinel unless the line was cut short. Verified under dash and on
Windows: with the line truncated the RC never appears and the probe
still does.

Like the RC sentinel, the probe marker is assembled by the remote, so
neither the PTY echoing the line back nor a command printing its own
stdin can be taken for it. Cost is one 55-byte message per -c run.

Detection cannot prevent the partial execution that already happened; it
replaces a silent hang with a clear error, and the error names no
character count, since every such figure belongs to one shell only.

Verified live: on Windows 8190 still runs and 8191 reports in 2 s rather
than timing out; exit codes, a 1 MB bash command and 60 KB byte-exact
round-trips all unaffected, and a stdin-reading command does not
false-positive.

Fixes #3.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01MvidAFW9a2r4hTgHPW9ywG
@ale-rinaldi
ale-rinaldi force-pushed the fix/windows-command-line-limit branch from f12584d to 89b6610 Compare September 5, 2026 16:13
@ale-rinaldi ale-rinaldi changed the title shell: refuse a -c command cmd.exe would truncate, instead of hanging shell: report a truncated -c command line instead of hanging on it Sep 5, 2026
@ale-rinaldi
ale-rinaldi merged commit 8d7c6e2 into main Sep 5, 2026
1 check passed
@ale-rinaldi
ale-rinaldi deleted the fix/windows-command-line-limit branch September 5, 2026 16:14
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.

-c hangs instead of erroring when the command exceeds cmd.exe's line limit

1 participant