Skip to content

fix(core): preserve FORCE_COLOR=0 intent for forked child tasks#35293

Open
comp615 wants to merge 1 commit intonrwl:masterfrom
comp615:fix/force-color-propagation
Open

fix(core): preserve FORCE_COLOR=0 intent for forked child tasks#35293
comp615 wants to merge 1 commit intonrwl:masterfrom
comp615:fix/force-color-propagation

Conversation

@comp615
Copy link
Copy Markdown
Contributor

@comp615 comp615 commented Apr 14, 2026

Note: An alternative to this PR is to wait for the upstream picocolors#100 fix and then remove the FORCE_COLOR=0 workaround in bin/nx.ts entirely. However, picocolors has not had a release or meaningful activity in over two years and appears to be unmaintained, so this fix ensures correct behavior in the meantime.

Current Behavior

When FORCE_COLOR=0 is set (common in CI to suppress ANSI codes), bin/nx.ts deletes it from process.env as a workaround for picocolors#100. However, task-env.ts and task-orchestrator.ts then default the undefined FORCE_COLOR to 'true' for all forked child tasks, re-enabling ANSI colors in every child process.

User sets FORCE_COLOR=0
  → bin/nx.ts deletes FORCE_COLOR, sets NO_COLOR=1
  → task-env.ts sees FORCE_COLOR === undefined → defaults to 'true'
  → child processes receive FORCE_COLOR=true (overrides NO_COLOR)
  → ANSI escape codes in ESLint, TypeScript, Vitest output

Expected Behavior

FORCE_COLOR=0 should propagate to child tasks, resulting in no ANSI escape codes.

Solution

  1. bin/nx.ts: Save the original value in NX_ORIGINAL_FORCE_COLOR before deleting
  2. task-env.ts: Extract a getForceColorForChild() helper that checks NX_ORIGINAL_FORCE_COLOR when FORCE_COLOR is undefined
  3. task-orchestrator.ts: Use the shared helper at both call sites

Impact

This affects any CI environment that sets FORCE_COLOR=0. In our case, ANSI escape codes in ESLint output broke downstream log parsers that use regex to extract lint errors (the ✖ N problems summary line contains invisible ANSI bytes that prevent matching).

Tests

Added 4 unit tests for getForceColorForChild() covering:

  • Explicit FORCE_COLOR passthrough
  • FORCE_COLOR=0 → deleted → restored via NX_ORIGINAL_FORCE_COLOR
  • Default to 'true' when neither is set
  • FORCE_COLOR takes precedence over NX_ORIGINAL_FORCE_COLOR

Fixes #35292

🤖 This PR was drafted with the help of AI

@comp615 comp615 requested a review from a team as a code owner April 14, 2026 15:02
@comp615 comp615 requested a review from leosvelperez April 14, 2026 15:02
@netlify
Copy link
Copy Markdown

netlify bot commented Apr 14, 2026

👷 Deploy request for nx-docs pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 4bcdfac

@netlify
Copy link
Copy Markdown

netlify bot commented Apr 14, 2026

👷 Deploy request for nx-dev pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 4bcdfac

@comp615 comp615 force-pushed the fix/force-color-propagation branch from a314699 to 901bd05 Compare April 14, 2026 15:13
@comp615
Copy link
Copy Markdown
Contributor Author

comp615 commented Apr 14, 2026

@FrozenPandaz FYI

Also note that I think it might be OK if force-color true wasn't set in CI

When FORCE_COLOR=0 is set in the environment, bin/nx.ts deletes it
(workaround for picocolors treating '0' as truthy). However, task-env.ts
and task-orchestrator.ts then default the undefined FORCE_COLOR to 'true'
for all forked children, re-enabling ANSI colors.

Save the original FORCE_COLOR value in NX_ORIGINAL_FORCE_COLOR before
deleting, and consult it when building child process environments.
Extract the logic into a shared getForceColorForChild() helper.

Fixes nrwl#35292

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019d8c4e-0d90-7126-b438-be77211ef603
@AgentEnder AgentEnder force-pushed the fix/force-color-propagation branch from 901bd05 to 4bcdfac Compare April 17, 2026 04:27
@nx-cloud
Copy link
Copy Markdown
Contributor

nx-cloud bot commented Apr 17, 2026

View your CI Pipeline Execution ↗ for commit 4bcdfac

Command Status Duration Result
nx affected --targets=lint,test,build,e2e,e2e-c... ⛔ Cancelled 1h 39m 42s View ↗
nx run-many -t check-imports check-lock-files c... ✅ Succeeded 3s View ↗
nx-cloud record -- pnpm nx-cloud conformance:check ✅ Succeeded 18s View ↗
nx build workspace-plugin ✅ Succeeded <1s View ↗
nx-cloud record -- nx sync:check ✅ Succeeded 24s View ↗
nx-cloud record -- nx format:check ✅ Succeeded 15s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-17 06:55:40 UTC

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.

FORCE_COLOR=0 is deleted then re-introduced as 'true' for forked child tasks

2 participants