Skip to content

fix: sort object keys before JSON.stringify in transformProjectGraphForRust#35298

Open
omer-za wants to merge 1 commit intonrwl:masterfrom
omer-za:fix/deterministic-project-configuration-hash
Open

fix: sort object keys before JSON.stringify in transformProjectGraphForRust#35298
omer-za wants to merge 1 commit intonrwl:masterfrom
omer-za:fix/deterministic-project-configuration-hash

Conversation

@omer-za
Copy link
Copy Markdown
Contributor

@omer-za omer-za commented Apr 15, 2026

Summary

Fixes #35297

JSON.stringify() preserves JavaScript object key insertion order. In transformProjectGraphForRust, target options and configurations are serialized with JSON.stringify() and passed to the Rust native hasher, which hashes them as-is for ProjectConfiguration.

If any Nx plugin or the target-defaults merge step produces these objects with keys in a different insertion order on different CI runners, the serialized string changes, causing the ProjectConfiguration hash to become non-deterministic. This leads to:

  • Nx Cloud cache invalidation on CI reruns
  • Previously succeeded tasks being re-executed unnecessarily
  • Wasted CI compute time

The Fix

Adds a recursive sortObjectKeys helper that normalizes key order before serialization, making the ProjectConfiguration hash independent of JS object construction order.

Note: The Rust hasher already sorts target names before hashing (making the hash independent of target insertion order), but it does not normalize the content of the stringified options/configurations. This fix closes that gap.

Evidence

Tested locally using the native HashPlanner + TaskHasher APIs:

Without fix

Options string ProjectConfiguration hash
{"cwd":"...","env":{...},"command":"jest","passWithNoTests":true} 10839486168096120338
{"passWithNoTests":true,"command":"jest","env":{...},"cwd":"..."} 14689511571626992510

With fix

Reversed ALL target orders AND ALL options/configurations key orders for ALL projects across the entire project graph:

  • 530 ProjectConfiguration entries, 0 mismatches
  • Identical task hashes

Related

This is analogous to the fix in commit db31f30 which sorted keys before hashing for AllExternalDependencies via hashObject.

@omer-za omer-za requested a review from a team as a code owner April 15, 2026 09:54
@omer-za omer-za requested a review from FrozenPandaz April 15, 2026 09:54
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 15, 2026

Deploy Preview for nx-docs canceled.

Name Link
🔨 Latest commit b2ef079
🔍 Latest deploy log https://app.netlify.com/projects/nx-docs/deploys/69df6066ec658200080a1c6f

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 15, 2026

Deploy Preview for nx-dev canceled.

Name Link
🔨 Latest commit b2ef079
🔍 Latest deploy log https://app.netlify.com/projects/nx-dev/deploys/69df6066bfc4370008b9df19

…orRust

JSON.stringify() preserves JavaScript object key insertion order. The Rust
native hasher receives these serialized strings and hashes them as-is for
ProjectConfiguration. If any plugin or the target-defaults merge produces
options/configurations objects with keys in a different insertion order on
different CI runners, the serialized string changes, causing the
ProjectConfiguration hash to become non-deterministic.

This leads to Nx Cloud cache invalidation and unnecessary task re-execution
when rerunning failed CI pipelines.

The fix adds a recursive sortObjectKeys helper that normalizes key order
before serialization, making the hash independent of JS object construction
order.

Fixes nrwl#35297
@omer-za omer-za force-pushed the fix/deterministic-project-configuration-hash branch from b2ef079 to 0a44149 Compare April 15, 2026 10:08
@FrozenPandaz FrozenPandaz self-assigned this Apr 23, 2026
@FrozenPandaz FrozenPandaz added the priority: high High Priority (important issues which affect many people severely) label Apr 23, 2026
@nx-cloud
Copy link
Copy Markdown
Contributor

nx-cloud Bot commented Apr 23, 2026

View your CI Pipeline Execution ↗ for commit 0a44149

Command Status Duration Result
nx-cloud record -- nx format:check ❌ Failed 14s View ↗
nx run-many -t check-imports check-lock-files c... ✅ Succeeded 4s View ↗
nx-cloud record -- nx sync:check ✅ Succeeded 23s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-23 21:03:12 UTC

Copy link
Copy Markdown
Contributor

@nx-cloud nx-cloud Bot left a comment

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 applied a prettier formatting fix to packages/nx/src/native/transform-objects.ts to resolve the format:check failure. The configurations line introduced by the PR exceeded prettier's line length limit and needed to be wrapped across multiple lines. This change is purely cosmetic and does not affect the runtime behavior of the sortObjectKeys fix.

Tip

We verified this fix by re-running nx-cloud record -- nx format:check.

diff --git a/packages/nx/src/native/transform-objects.ts b/packages/nx/src/native/transform-objects.ts
index c4164ea1..3f4e03af 100644
--- a/packages/nx/src/native/transform-objects.ts
+++ b/packages/nx/src/native/transform-objects.ts
@@ -36,7 +36,9 @@ export function transformProjectGraphForRust(
         inputs: targetConfig.inputs,
         outputs: targetConfig.outputs,
         options: JSON.stringify(sortObjectKeys(targetConfig.options)),
-        configurations: JSON.stringify(sortObjectKeys(targetConfig.configurations)),
+        configurations: JSON.stringify(
+          sortObjectKeys(targetConfig.configurations)
+        ),
         parallelism: targetConfig.parallelism,
       };
     }

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

Because this branch comes from a fork, it is not possible for us to apply fixes directly, but you can apply the changes locally using the available options below.

Apply changes locally with:

npx nx-cloud apply-locally ois5-3knp

Apply fix locally with your editor ↗   View interactive diff ↗



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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: high High Priority (important issues which affect many people severely)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Non-deterministic ProjectConfiguration hash due to JSON.stringify key-order sensitivity in transformProjectGraphForRust

2 participants