fix(task): avoid duplicated stderr on task failure in replacing mode#8275
fix(task): avoid duplicated stderr on task failure in replacing mode#8275
Conversation
Summary of ChangesHello @jdx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses an issue where error messages from stderr were duplicated when tasks failed in the 'replacing' output mode. The core change involves distinguishing between stdout and stderr lines when accumulating output, ensuring that only stdout, which was previously hidden by progress indicators, is replayed upon task failure, thereby providing a cleaner and more accurate error presentation. Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
8ed0258 to
10cdab4
Compare
There was a problem hiding this comment.
Code Review
The pull request addresses a bug where stderr output was duplicated when a task failed in --output replacing mode. The fix involves tagging output lines as either stdout or stderr and replaying only stdout lines on error, as stderr was already printed during execution. This is a good fix that improves the user experience by preventing redundant output. The changes are well-tested and consider various output modes and success/failure scenarios.
There was a problem hiding this comment.
Pull request overview
This PR fixes a bug where stderr output was duplicated when a task failed in --output replacing mode. The fix distinguishes between stdout and stderr in the accumulated output buffer and only replays stdout on error, since stderr was already displayed during execution.
Changes:
- Modified output accumulation to track whether each line came from stdout or stderr using a tuple
(String, bool) - Updated
on_error()to filter and replay only stdout lines, preventing stderr duplication - Updated all
on_error()call sites to pass the newVec<(String, bool)>type instead ofString
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/cmd.rs
Outdated
| let line = self.redactor.redact(&line); | ||
| self.on_stdout(line.clone()); | ||
| combined_output.push(line); | ||
| combined_output.push((line, true)); |
There was a problem hiding this comment.
Consider using a more descriptive tuple field name or a struct to improve code readability. The boolean flag 'true' for stdout and 'false' for stderr is not immediately clear from the code. A struct like struct OutputLine { content: String, is_stdout: bool } or using a named tuple pattern would make the intent clearer and reduce the risk of confusion.
When a task fails in replacing output mode, on_error() re-printed all accumulated output (stdout + stderr) via pr.println(). But stderr lines were already printed during execution via pr.println() in on_stderr(), causing them to appear twice. Fix by tagging each output line with its source (stdout vs stderr) and only replaying stdout lines in on_error(). Stdout needs replay because it was only shown transiently via pr.set_message() (progress indicator), while stderr was already permanently printed. Also update CLAUDE.md to clarify that task-related changes should use the `task` scope, not `run`. Fixes #8267 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
10cdab4 to
5b1339e
Compare
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.17 x -- echo |
22.9 ± 1.1 | 21.8 | 35.0 | 1.00 |
mise x -- echo |
23.0 ± 1.6 | 21.6 | 38.8 | 1.01 ± 0.08 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.17 env |
22.0 ± 1.2 | 21.1 | 35.6 | 1.00 |
mise env |
22.5 ± 1.2 | 21.1 | 26.4 | 1.02 ± 0.08 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.17 hook-env |
22.7 ± 1.1 | 21.6 | 39.5 | 1.00 |
mise hook-env |
22.8 ± 0.5 | 22.0 | 25.1 | 1.01 ± 0.05 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.17 ls |
19.8 ± 0.3 | 19.2 | 22.0 | 1.00 |
mise ls |
19.9 ± 0.2 | 19.4 | 21.1 | 1.00 ± 0.02 |
xtasks/test/perf
| Command | mise-2026.2.17 | mise | Variance |
|---|---|---|---|
| install (cached) | 123ms | 124ms | +0% |
| ls (cached) | 75ms | 75ms | +0% |
| bin-paths (cached) | 79ms | 79ms | +0% |
| task-ls (cached) | 813ms | 800ms | +1% |
### 🚀 Features - **(install)** auto-lock all platforms after tool installation by @jdx in [#8277](#8277) ### 🐛 Bug Fixes - **(config)** respect --yes flag for config trust prompts by @jdx in [#8288](#8288) - **(exec)** strip shims from PATH on Unix to prevent infinite recursion by @jdx in [#8276](#8276) - **(install)** validate --locked before --dry-run short-circuit by @altendky in [#8290](#8290) - **(release)** refresh PATH after mise up in release-plz by @jdx in [#8292](#8292) - **(schema)** replace unevaluatedProperties with additionalProperties by @jdx in [#8285](#8285) - **(task)** avoid duplicated stderr on task failure in replacing mode by @jdx in [#8275](#8275) - **(task)** use process groups to kill child process trees on Unix by @jdx in [#8279](#8279) - **(task)** run depends_post tasks even when parent task fails by @jdx in [#8274](#8274) - **(task)** suggest similar commands when mistyping a CLI subcommand by @jdx in [#8286](#8286) - **(task)** execute monorepo subdirectory prepare steps from root by @jdx in [#8291](#8291) - **(upgrade)** don't force-reinstall already installed versions by @jdx in [#8282](#8282) - **(watch)** restore terminal state after watchexec exits by @jdx in [#8273](#8273) ### 📚 Documentation - clarify that MISE_CEILING_PATHS excludes the ceiling directory itself by @jdx in [#8283](#8283) ### Chore - replace gen-release-notes script with communique by @jdx in [#8289](#8289) ### New Contributors - @altendky made their first contribution in [#8290](#8290) ## 📦 Aqua Registry Updates #### New Packages (4) - [`Skarlso/crd-to-sample-yaml`](https://github.com/Skarlso/crd-to-sample-yaml) - [`kunobi-ninja/kunobi-releases`](https://github.com/kunobi-ninja/kunobi-releases) - [`swanysimon/markdownlint-rs`](https://github.com/swanysimon/markdownlint-rs) - [`tmux/tmux-builds`](https://github.com/tmux/tmux-builds) #### Updated Packages (2) - [`firecow/gitlab-ci-local`](https://github.com/firecow/gitlab-ci-local) - [`k1LoW/runn`](https://github.com/k1LoW/runn)
## [2026.2.18](https://github.com/jdx/mise/compare/v2026.2.17..v2026.2.18) - 2026-02-21 ### 🚀 Features - **(install)** auto-lock all platforms after tool installation by @jdx in [#8277](jdx/mise#8277) ### 🐛 Bug Fixes - **(config)** respect --yes flag for config trust prompts by @jdx in [#8288](jdx/mise#8288) - **(exec)** strip shims from PATH on Unix to prevent infinite recursion by @jdx in [#8276](jdx/mise#8276) - **(install)** validate --locked before --dry-run short-circuit by @altendky in [#8290](jdx/mise#8290) - **(release)** refresh PATH after mise up in release-plz by @jdx in [#8292](jdx/mise#8292) - **(schema)** replace unevaluatedProperties with additionalProperties by @jdx in [#8285](jdx/mise#8285) - **(task)** avoid duplicated stderr on task failure in replacing mode by @jdx in [#8275](jdx/mise#8275) - **(task)** use process groups to kill child process trees on Unix by @jdx in [#8279](jdx/mise#8279) - **(task)** run depends_post tasks even when parent task fails by @jdx in [#8274](jdx/mise#8274) - **(task)** suggest similar commands when mistyping a CLI subcommand by @jdx in [#8286](jdx/mise#8286) - **(task)** execute monorepo subdirectory prepare steps from root by @jdx in [#8291](jdx/mise#8291) - **(upgrade)** don't force-reinstall already installed versions by @jdx in [#8282](jdx/mise#8282) - **(watch)** restore terminal state after watchexec exits by @jdx in [#8273](jdx/mise#8273) ### 📚 Documentation - clarify that MISE_CEILING_PATHS excludes the ceiling directory itself by @jdx in [#8283](jdx/mise#8283) ### Chore - replace gen-release-notes script with communique by @jdx in [#8289](jdx/mise#8289) ### New Contributors - @altendky made their first contribution in [#8290](jdx/mise#8290) ### 📦 Aqua Registry Updates #### New Packages (4) - [`Skarlso/crd-to-sample-yaml`](https://github.com/Skarlso/crd-to-sample-yaml) - [`kunobi-ninja/kunobi-releases`](https://github.com/kunobi-ninja/kunobi-releases) - [`swanysimon/markdownlint-rs`](https://github.com/swanysimon/markdownlint-rs) - [`tmux/tmux-builds`](https://github.com/tmux/tmux-builds) #### Updated Packages (2) - [`firecow/gitlab-ci-local`](https://github.com/firecow/gitlab-ci-local) - [`k1LoW/runn`](https://github.com/k1LoW/runn) ## [2026.2.17](https://github.com/jdx/mise/compare/v2026.2.16..v2026.2.17) - 2026-02-19 ### 🚀 Features - **(prepare)** update mtime of outputs after command is run by @halms in [#8243](jdx/mise#8243) ### 🐛 Bug Fixes - **(install)** use backend bin paths for per-tool postinstall hooks by @jdx in [#8234](jdx/mise#8234) - **(use)** write to config.toml instead of config.local.toml by @jdx in [#8240](jdx/mise#8240) - default legacy .mise.backend installs to non-explicit by @jean-humann in [#8245](jdx/mise#8245) ### 🚜 Refactor - **(config)** consolidate flat task_* settings into nested task.* by @jdx in [#8239](jdx/mise#8239) ### Chore - **(prepare)** refactor common code into ProviderBase by @halms in [#8246](jdx/mise#8246) ### 📦 Aqua Registry Updates #### Updated Packages (1) - [`namespacelabs/foundation/nsc`](https://github.com/namespacelabs/foundation/nsc)
…dx#8275) ## Summary - When a task fails in `--output replacing` mode, `on_error()` re-printed all accumulated output (stdout + stderr) via `pr.println()`, but stderr was already printed during execution, causing duplication - Fix by tagging each output line with its source (stdout vs stderr) and only replaying stdout lines in `on_error()`, since stdout was hidden behind the progress indicator (`pr.set_message()`) while stderr was already permanently visible Fixes jdx#8267 ## Test plan - [x] Verified `--output replacing` no longer duplicates stderr on task failure - [x] Verified stdout is still shown on failure (it was hidden behind progress indicator) - [x] Verified all other output modes (default, prefix, interleave, raw, quiet, silent, timed, keep-order) are unaffected - [x] Verified successful tasks are unaffected - [x] All 481 unit tests pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Small, localized change to command output handling on failures; main risk is inadvertently suppressing or mis-ordering error output in edge cases. > > **Overview** > Fixes a failure-mode logging bug where `--output replacing` could duplicate stderr by replaying all captured output on error. > > `CmdLineRunner` now tags captured lines with an `OutputSource` and updates `on_error` to replay **only stdout** (and only when stdout was hidden behind the progress indicator), leaving stderr to be shown just once during execution. Also updates the raw-exec error path to pass an empty output vector and tweaks contributor guidance in `CLAUDE.md` to prefer the `task` scope for task-related changes. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 5b1339e. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
### 🚀 Features - **(install)** auto-lock all platforms after tool installation by @jdx in [jdx#8277](jdx#8277) ### 🐛 Bug Fixes - **(config)** respect --yes flag for config trust prompts by @jdx in [jdx#8288](jdx#8288) - **(exec)** strip shims from PATH on Unix to prevent infinite recursion by @jdx in [jdx#8276](jdx#8276) - **(install)** validate --locked before --dry-run short-circuit by @altendky in [jdx#8290](jdx#8290) - **(release)** refresh PATH after mise up in release-plz by @jdx in [jdx#8292](jdx#8292) - **(schema)** replace unevaluatedProperties with additionalProperties by @jdx in [jdx#8285](jdx#8285) - **(task)** avoid duplicated stderr on task failure in replacing mode by @jdx in [jdx#8275](jdx#8275) - **(task)** use process groups to kill child process trees on Unix by @jdx in [jdx#8279](jdx#8279) - **(task)** run depends_post tasks even when parent task fails by @jdx in [jdx#8274](jdx#8274) - **(task)** suggest similar commands when mistyping a CLI subcommand by @jdx in [jdx#8286](jdx#8286) - **(task)** execute monorepo subdirectory prepare steps from root by @jdx in [jdx#8291](jdx#8291) - **(upgrade)** don't force-reinstall already installed versions by @jdx in [jdx#8282](jdx#8282) - **(watch)** restore terminal state after watchexec exits by @jdx in [jdx#8273](jdx#8273) ### 📚 Documentation - clarify that MISE_CEILING_PATHS excludes the ceiling directory itself by @jdx in [jdx#8283](jdx#8283) ### Chore - replace gen-release-notes script with communique by @jdx in [jdx#8289](jdx#8289) ### New Contributors - @altendky made their first contribution in [jdx#8290](jdx#8290) ## 📦 Aqua Registry Updates #### New Packages (4) - [`Skarlso/crd-to-sample-yaml`](https://github.com/Skarlso/crd-to-sample-yaml) - [`kunobi-ninja/kunobi-releases`](https://github.com/kunobi-ninja/kunobi-releases) - [`swanysimon/markdownlint-rs`](https://github.com/swanysimon/markdownlint-rs) - [`tmux/tmux-builds`](https://github.com/tmux/tmux-builds) #### Updated Packages (2) - [`firecow/gitlab-ci-local`](https://github.com/firecow/gitlab-ci-local) - [`k1LoW/runn`](https://github.com/k1LoW/runn)
Summary
--output replacingmode,on_error()re-printed all accumulated output (stdout + stderr) viapr.println(), but stderr was already printed during execution, causing duplicationon_error(), since stdout was hidden behind the progress indicator (pr.set_message()) while stderr was already permanently visibleFixes #8267
Test plan
--output replacingno longer duplicates stderr on task failure🤖 Generated with Claude Code
Note
Low Risk
Small, localized change to command output handling on failures; main risk is inadvertently suppressing or mis-ordering error output in edge cases.
Overview
Fixes a failure-mode logging bug where
--output replacingcould duplicate stderr by replaying all captured output on error.CmdLineRunnernow tags captured lines with anOutputSourceand updateson_errorto replay only stdout (and only when stdout was hidden behind the progress indicator), leaving stderr to be shown just once during execution. Also updates the raw-exec error path to pass an empty output vector and tweaks contributor guidance inCLAUDE.mdto prefer thetaskscope for task-related changes.Written by Cursor Bugbot for commit 5b1339e. This will update automatically on new commits. Configure here.