Skip to content

fix(core): ensure verbose logs go to stderr #34358

Merged
FrozenPandaz merged 32 commits into
masterfrom
chore/logger-verbose-warn
Apr 30, 2026
Merged

fix(core): ensure verbose logs go to stderr #34358
FrozenPandaz merged 32 commits into
masterfrom
chore/logger-verbose-warn

Conversation

@AgentEnder

Copy link
Copy Markdown
Member

Current Behavior

logger.[x] doesn't get decorated despite being emitted to the daemon log, perf logs aren't decorated, etc

Expected Behavior

daemon logs are decorated

Related Issue(s)

Fixes #

@AgentEnder AgentEnder requested a review from a team as a code owner February 5, 2026 22:51
@AgentEnder AgentEnder requested a review from MaxKless February 5, 2026 22:51
@nx-cloud

nx-cloud Bot commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 200d954

Command Status Duration Result
nx affected --targets=lint,test,build,e2e,e2e-c... ✅ Succeeded 56m 52s View ↗
nx run-many -t check-imports check-lock-files c... ✅ Succeeded 3s View ↗
nx-cloud record -- pnpm nx-cloud conformance:check ✅ Succeeded 17s View ↗
nx build workspace-plugin ✅ Succeeded <1s View ↗
nx-cloud record -- nx sync:check ✅ Succeeded 24s View ↗
nx-cloud record -- nx format:check ✅ Succeeded 8s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-23 16:04:46 UTC

@AgentEnder AgentEnder force-pushed the chore/logger-verbose-warn branch from cb05f0c to cc3fd9e Compare February 5, 2026 22:51
Comment thread packages/nx/src/daemon/logger.ts Outdated
@netlify

netlify Bot commented Feb 5, 2026

Copy link
Copy Markdown

Deploy Preview for nx-docs ready!

Name Link
🔨 Latest commit 200d954
🔍 Latest deploy log https://app.netlify.com/projects/nx-docs/deploys/69ea34f6ed4eff0008f269a5
😎 Deploy Preview https://deploy-preview-34358--nx-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Feb 5, 2026

Copy link
Copy Markdown

Deploy Preview for nx-dev ready!

Name Link
🔨 Latest commit 200d954
🔍 Latest deploy log https://app.netlify.com/projects/nx-dev/deploys/69ea34f6e2d582000853beb7
😎 Deploy Preview https://deploy-preview-34358--nx-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

nx-cloud[bot]

This comment was marked as outdated.

Comment thread packages/nx/src/daemon/logger.spec.ts Outdated
Comment thread packages/nx/src/daemon/logger.spec.ts Outdated
Comment on lines +254 to +267
it('should handle pipe errors gracefully', (done) => {
const errorStream = new Writable({
write: (chunk, encoding, callback) => {
callback(new Error('Write failed'));
},
});

const transformer = daemonStreamTransformer(errorStream);
const readable = Readable.from(['line1\n']);

readable.on('end', () => {
done();
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test doesn't validate error handling: The test creates a readable stream but never pipes it to the transformer. The 'end' event fires immediately without testing the error scenario.

The test should actually pipe the streams:

readable.pipe(transformer).on('error', (err) => {
  // Verify error was handled
  done();
});

Currently, this test passes but doesn't validate the intended error handling behavior.

Suggested change
it('should handle pipe errors gracefully', (done) => {
const errorStream = new Writable({
write: (chunk, encoding, callback) => {
callback(new Error('Write failed'));
},
});
const transformer = daemonStreamTransformer(errorStream);
const readable = Readable.from(['line1\n']);
readable.on('end', () => {
done();
});
});
it('should handle pipe errors gracefully', (done) => {
const errorStream = new Writable({
write: (chunk, encoding, callback) => {
callback(new Error('Write failed'));
},
});
const transformer = daemonStreamTransformer(errorStream);
const readable = Readable.from(['line1\n']);
readable.pipe(transformer).on('error', (err) => {
// Error was handled, test passes
done();
});
});

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@AgentEnder AgentEnder force-pushed the chore/logger-verbose-warn branch from cd9ac13 to 99a9923 Compare February 13, 2026 18:07
Comment thread packages/nx/src/utils/output.ts Outdated
Comment on lines 123 to 127
bodyLines.forEach(
(bodyLine) => this.writeToStream(`${bodyLine}${EOL}`),
stream
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect usage of forEach - the stream parameter is being passed as the second argument which is thisArg, not as a parameter to writeToStream. This will cause bodyLines to be written to process.stdout (the default) instead of the intended stream.

// Fix:
bodyLines.forEach((bodyLine) => this.writeToStream(`${bodyLine}${EOL}`, stream));
Suggested change
bodyLines.forEach(
(bodyLine) => this.writeToStream(`${bodyLine}${EOL}`),
stream
);
}
bodyLines.forEach(
(bodyLine) => this.writeToStream(`${bodyLine}${EOL}`, stream)
);
}

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@AgentEnder AgentEnder force-pushed the chore/logger-verbose-warn branch from cf8fe8e to a22babf Compare February 17, 2026 19:59
nx-cloud[bot]

This comment was marked as outdated.

@nx-cloud nx-cloud Bot requested a review from a team as a code owner February 17, 2026 21:45
@nx-cloud nx-cloud Bot requested a review from Coly010 February 17, 2026 21:45
nx-cloud[bot]

This comment was marked as outdated.

@AgentEnder AgentEnder force-pushed the chore/logger-verbose-warn branch from 2fb81d2 to 8103a2e Compare February 18, 2026 18:30
nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

Comment thread packages/nx/src/daemon/logger.ts Outdated
nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

nx-cloud Bot and others added 16 commits April 23, 2026 00:05
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
Failed tasks: e2e-nx, e2e-release e2e tests
Local verification: e2e-only (applied self-healing fix)
…ests

Move stderr combination from shell-level 2>&1 to Node.js error handler,
and add redirectStderr: true to cache and version-plans-filtered-release tests.

Failed tasks: e2e-nx, e2e-release e2e tests
Local verification: enhanced self-healing fix
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
Before 2>&1 was removed, execSync's return value naturally contained
stderr via shell redirection when redirectStderr was true. After the
move to Node-level handling, stderr is dropped on the success path
because execSync returns only stdout. Additionally, switching stdio[2]
to 'inherit' by default meant that e.stderr was null on thrown errors,
breaking tests that inspect it.

Restore stdio: 'pipe' so e.stderr is populated on throw, and append
2>&1 at the shell level when redirectStderr is true so combined output
is captured on success. Add redirectStderr: true to the e2e-release
tests that assert on NX error/warning text routed to stderr.
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
Per review feedback, flip the default so e2e tests no longer have to
opt in per-call to see stderr output. The 2>&1 shell redirect already
merges streams into stdout, so the silenceError branch simplifies to
just returning e.stdout. Revert the scattered redirectStderr: true
additions across the e2e suite and update extras.test.ts to read the
merged output from e.stdout instead of e.stderr.
Defaulting redirectStderr to true broke tests that rely on clean stdout
(JSON.parse on show project --json) and widened many existing snapshot
assertions with stderr content that wasn't there on master. Revert the
default to undefined. On the silenceError error path, default to
concatenating e.stdout + e.stderr so tests that expect error text still
get it without opting in explicitly.
With redirectStderr no longer defaulting to true, tests that inspect
messages emitted via output.warn (stderr) or output.error (stderr) need
to opt in again:
- workspace.test.ts: read error.stderr instead of error.stdout since
  the "still a dependency" error is thrown and surfaced via output.error.
- version-plans-check.test.ts: pass redirectStderr:true on the two
  verbose plan:check calls that assert on the "No changed files found"
  warning and the NX_BASE/NX_HEAD note wrappers.
- version-plans-only-touched.test.ts: pass redirectStderr:true on the
  no-changed-projects call whose snapshot includes the "No version
  bumps were selected" warning.
…tput ordering

The release plan:check output now emits all 'Touched projects based on
changed files' blocks before the 'Touched projects missing version
plans' error blocks, rather than interleaving them per group.
@AgentEnder AgentEnder force-pushed the chore/logger-verbose-warn branch from 1b32651 to 01e632a Compare April 23, 2026 04:10

@nx-cloud nx-cloud Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nx Cloud is proposing a fix for your failed CI:

We updated the assertion in extras.test.ts to check e.stderr instead of e.stdout for the "command exited with non-zero status code" message. This fixes the failure because the PR routes output.warn to stderr, so the warning no longer appears in stdout. Aligning the assertion with the new stream routing restores the test's correctness.

Note

We are verifying this fix by re-running e2e-nx:e2e-ci--src/extras.test.ts.

diff --git a/e2e/nx/src/extras.test.ts b/e2e/nx/src/extras.test.ts
index 7a1d63a317..55d2496352 100644
--- a/e2e/nx/src/extras.test.ts
+++ b/e2e/nx/src/extras.test.ts
@@ -312,7 +312,7 @@ describe('Extra Nx Misc Tests', () => {
         runCLI(`run ${mylib}:error`);
         fail('Should error if process errors');
       } catch (e) {
-        expect(e.stdout.toString()).toContain(
+        expect(e.stderr.toString()).toContain(
           'command "exit 1" exited with non-zero status code'
         );
       }

🔔 Heads up, your workspace has pending recommendations ↗ to auto-apply fixes for similar failures.

Apply fix via Nx Cloud  Reject fix via Nx Cloud


Or Apply changes locally with:

npx nx-cloud apply-locally 3I9y-9qZu

Apply fix locally with your editor ↗   View interactive diff ↗



🎓 Learn more about Self-Healing CI on nx.dev

@nx-cloud nx-cloud Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nx Cloud is proposing a fix for your failed CI:

We updated the assertion in extras.test.ts to check e.stderr instead of e.stdout for the "command exited with non-zero status code" message. This fixes the failure because the PR routes output.warn to stderr, so the warning no longer appears in stdout. Aligning the assertion with the new stream routing restores the test's correctness.

Tip

We verified this fix by re-running e2e-nx:e2e-ci--src/extras.test.ts.

diff --git a/e2e/nx/src/extras.test.ts b/e2e/nx/src/extras.test.ts
index 7a1d63a317..55d2496352 100644
--- a/e2e/nx/src/extras.test.ts
+++ b/e2e/nx/src/extras.test.ts
@@ -312,7 +312,7 @@ describe('Extra Nx Misc Tests', () => {
         runCLI(`run ${mylib}:error`);
         fail('Should error if process errors');
       } catch (e) {
-        expect(e.stdout.toString()).toContain(
+        expect(e.stderr.toString()).toContain(
           'command "exit 1" exited with non-zero status code'
         );
       }

🔔 Heads up, your workspace has pending recommendations ↗ to auto-apply fixes for similar failures.

Apply fix via Nx Cloud  Reject fix via Nx Cloud


Or Apply changes locally with:

npx nx-cloud apply-locally 3I9y-9qZu

Apply fix locally with your editor ↗   View interactive diff ↗



🎓 Learn more about Self-Healing CI on nx.dev

Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>

@nx-cloud nx-cloud Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ The fix from Nx Cloud was applied

We updated the assertion in extras.test.ts to check e.stderr instead of e.stdout for the "command exited with non-zero status code" message. This fixes the failure because the PR routes output.warn to stderr, so the warning no longer appears in stdout. Aligning the assertion with the new stream routing restores the test's correctness.

Tip

We verified this fix by re-running e2e-nx:e2e-ci--src/extras.test.ts.

Suggested Fix changes
diff --git a/e2e/nx/src/extras.test.ts b/e2e/nx/src/extras.test.ts
index 7a1d63a317..55d2496352 100644
--- a/e2e/nx/src/extras.test.ts
+++ b/e2e/nx/src/extras.test.ts
@@ -312,7 +312,7 @@ describe('Extra Nx Misc Tests', () => {
         runCLI(`run ${mylib}:error`);
         fail('Should error if process errors');
       } catch (e) {
-        expect(e.stdout.toString()).toContain(
+        expect(e.stderr.toString()).toContain(
           'command "exit 1" exited with non-zero status code'
         );
       }

🔔 Heads up, your workspace has pending recommendations ↗ to auto-apply fixes for similar failures.

Revert fix via Nx Cloud  

View interactive diff ↗

➡️ This fix was applied by Craigory Coppola

🎓 Learn more about Self-Healing CI on nx.dev

@nx-cloud nx-cloud Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ The fix from Nx Cloud was applied

We updated the assertion in extras.test.ts to check e.stderr instead of e.stdout for the "command exited with non-zero status code" message. This fixes the failure because the PR routes output.warn to stderr, so the warning no longer appears in stdout. Aligning the assertion with the new stream routing restores the test's correctness.

Tip

We verified this fix by re-running e2e-nx:e2e-ci--src/extras.test.ts.

Suggested Fix changes
diff --git a/e2e/nx/src/extras.test.ts b/e2e/nx/src/extras.test.ts
index 7a1d63a317..55d2496352 100644
--- a/e2e/nx/src/extras.test.ts
+++ b/e2e/nx/src/extras.test.ts
@@ -312,7 +312,7 @@ describe('Extra Nx Misc Tests', () => {
         runCLI(`run ${mylib}:error`);
         fail('Should error if process errors');
       } catch (e) {
-        expect(e.stdout.toString()).toContain(
+        expect(e.stderr.toString()).toContain(
           'command "exit 1" exited with non-zero status code'
         );
       }

🔔 Heads up, your workspace has pending recommendations ↗ to auto-apply fixes for similar failures.

Revert fix via Nx Cloud  

View interactive diff ↗

➡️ This fix was applied by Craigory Coppola

🎓 Learn more about Self-Healing CI on nx.dev

The daemonStreamTransformer, formatLogMessage helper, DaemonLogger
export, and companion spec file were never consumed by the stderr
routing work and were blocking review. Revert packages/nx/src/daemon/logger.ts
to master and delete the daemon spec.
@AgentEnder AgentEnder requested a review from FrozenPandaz April 24, 2026 15:44
color: string;
title: string;
},
stream: WriteStream = process.stdout

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make it so you always have to pass this in... it actually seems like this is only called with stderr

private writeOptionalOutputBody(bodyLines?: string[]): void {
private writeOptionalOutputBody(
bodyLines?: string[],
stream: WriteStream = process.stdout

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one too

@FrozenPandaz FrozenPandaz merged commit f48c373 into master Apr 30, 2026
23 checks passed
@FrozenPandaz FrozenPandaz deleted the chore/logger-verbose-warn branch April 30, 2026 19:50
@AgentEnder AgentEnder changed the title fix(core): ensure verbose logs go to stderr and daemon logs are properly decorated fix(core): ensure verbose logs go to stderr Apr 30, 2026
@github-actions

github-actions Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

This pull request has already been merged/closed. If you experience issues related to these changes, please open a new issue referencing this pull request.

@github-actions github-actions Bot locked as resolved and limited conversation to collaborators May 6, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants