Skip to content

Honor stdout and stderr false in Container#exec - #609

Open
tas50 wants to merge 1 commit into
upserve:masterfrom
tas50:fix-exec-stream-selection
Open

Honor stdout and stderr false in Container#exec#609
tas50 wants to merge 1 commit into
upserve:masterfrom
tas50:fix-exec-stream-selection

Conversation

@tas50

@tas50 tas50 commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Container#exec resolved its stream options with

stdout = options.delete(:stdout) || !detach
stderr = options.delete(:stderr) || !detach

An explicit false is falsy, so it fell through to !detach and came back as true. Neither stream could be switched off.

The README documented container.exec(["date"], stderr: false) as the way to capture only stdout. It never did:

stderr: false  ->  stdout=["O\n"] stderr=["E\n"]   # not suppressed

The fix

Test for the key rather than its truthiness, keeping !detach as the default when the caller says nothing:

stdout = options.key?(:stdout) ? options.delete(:stdout) : !detach
stderr = options.key?(:stderr) ? options.delete(:stderr) : !detach

Verification

Two specs, both confirmed failing before the change:

expected `["err\n"].empty?` to be truthy, got false    # stderr: false
expected `["out\n"].empty?` to be truthy, got false    # stdout: false

Both pass after. The existing #exec examples — default behaviour, detach: true, block streaming, tty — are unchanged, and exec_spec is 11 examples / 0 failures.

Compatibility

Passing detach:, or passing nothing, behaves exactly as before. Only an explicit stdout: false / stderr: false changes, and that is the documented behaviour finally working rather than a contract anyone could have depended on.

Note on CI

#exec when stdin object is passed fails on this branch, but is pre-existing on master — I confirmed master alone reports 5 examples, 1 failure for that same spec. It is the hijack/attach issue and only reproduces on Docker Desktop; it passes on the Linux runners. CI will also stay red here until #605 lands.

Container#exec resolved its stream options with

    stdout = options.delete(:stdout) || !detach
    stderr = options.delete(:stderr) || !detach

so an explicit false fell through to `!detach` and came back as true. Neither
stream could actually be switched off. The README documented
`container.exec(['date'], stderr: false)` as a way to capture only stdout; it
never did:

    stdout=["O\n"] stderr=["E\n"]   # stderr: false

Test for the key rather than its truthiness, keeping !detach as the default
when the caller says nothing. Passing detach, or passing nothing, behaves
exactly as before.
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.

1 participant