Skip to content

Fix --quiet not suppressing warnings when stdout is redirected - #1995

Open
tbszz wants to merge 1 commit into
httpie:masterfrom
tbszz:fix/quiet-warnings-with-redirected-stdout
Open

tbszz wants to merge 1 commit into
httpie:masterfrom
tbszz:fix/quiet-warnings-with-redirected-stdout

Conversation

@tbszz

@tbszz tbszz commented Nov 2, 2026

Copy link
Copy Markdown

Description

--quiet does not suppress warnings/info messages when stdout is redirected (piped to a file or another process), contradicting the documented behavior of the flag:

Do not print to stdout or stderr, except for errors and warnings when provided once. Provide twice to suppress warnings as well.
— http --help

Fixes #1978

Reproduction (on unmodified master)

Any warning emitted while stdout is redirected leaks to stderr even with -qq. Using a local server that returns HTTP 500:

$ http --quiet --quiet --check-status GET http://127.0.0.1:18974/ > out.json   # note: stderr shown below
http: warning: HTTP 500 Internal Server Error

Same happens for e.g. an invalid config file (http: warning: invalid config file ...).

Root cause

Environment.log_error() gates the quiet-threshold check on self.stdout_isatty (httpie/context.py):

if self.stdout_isatty and self.quiet >= LOG_LEVEL_DISPLAY_THRESHOLDS[level]:
    stderr = self.stderr          # under --quiet this is devnull
else:
    stderr = self._orig_stderr    # always the real stderr

When stdout is not a TTY the condition short-circuits to _orig_stderr, so the message is printed regardless of the quiet level. The stdout_isatty gate was introduced together with the original --quiet implementation in #1175 / #1283; no test or discussion back then named piping semantics, and test_quiet_quiet_with_check_status_non_zero_pipe ended up pinning the buggy behavior.

Fix

Drop self.stdout_isatty from the condition so the quiet level decides alone:

  • -qq + redirected stdout: warnings/info are suppressed (via the devnull'd self.stderr), same as on a TTY.
  • Single -q: warnings still shown, on TTY and pipes alike.
  • Errors: never hidden (LOG_LEVEL_DISPLAY_THRESHOLDS[ERROR] is infinite).
  • No-quiet path: unchanged.

test_quiet_quiet_with_check_status_non_zero_pipe is flipped to assert the documented suppression (it previously asserted the bug).

Verification

  • Regression evidence: the flipped test fails on unmodified master (assert not r.stderr vs actual 'http: warning: HTTP 500...') and passes with the fix. The TTY twin (test_quiet_quiet_with_check_status_non_zero) passes before and after (control).
  • Live before/after with the same local HTTP 500 server and > out.json redirection: unmodified master prints http: warning: HTTP 500 Internal Server Error on stderr with -qq; with the fix stderr is empty; with a single -q the warning is still printed.
  • Full suite (Windows, Python 3.13): with fix 989 passed / 5 failed / 11 errors; unmodified master in the same environment yields the identical failure set (Windows-specific DNS error text, CLI usage-text formatting, update-warnings fixture errors) — no regressions introduced.

Environment.log_error() gated the quiet threshold check on
stdout_isatty, so when stdout was redirected (e.g. piping output in a
script) every warning and info message bypassed the devnull'd stderr
and was printed to the original stderr even with -q/-qq, contradicting
the documented behavior of --quiet ('Provide twice to suppress
warnings as well.').

Drop the stdout_isatty condition: with the appropriate quiet level,
messages now go through self.stderr (devnull under --quiet) regardless
of whether stdout is a TTY. Single -q still shows warnings, errors are
never hidden (their threshold is infinite), and the not-quiet path is
unchanged.

Also flips test_quiet_quiet_with_check_status_non_zero_pipe, which
pinned the buggy behavior, to assert documented suppression.

Fixes httpie#1978
@tbszz

tbszz commented Nov 3, 2026

Copy link
Copy Markdown
Author

Noticed #1992 addresses the same issue (#1978) with the same one-line root-cause fix (dropping stdout_isatty from the log_error condition) — happy to defer to whichever the maintainers prefer.

One difference worth flagging: this PR also updates test_quiet_quiet_with_check_status_non_zero_pipe, which currently pins the buggy behavior (assert 'http: warning: HTTP 500' in r.stderr). With the fix applied, that assertion fails, so the test has to be flipped along with the change for the suite to stay consistent. Also included a CHANGELOG entry.

For context on the red CI: the test workflow is failing on master as well (e.g. runs from 2026-08-29 on the latest master commit are all failure/cancelled), so those failures don't come from this change.

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.

Bug: log_error ignores --quiet flag when stdout is redirected

1 participant