Skip to content

pixi update and pixi lock --check alternate source dependency order and identifier hash #7000

Closed

Description

@rwgk

Checks

  • I searched for existing reports. #6161 is related but describes a separate source-selection problem, explained below.
  • I reproduced this with Pixi 0.80.0 and a source build of current main at 56ae6f3.

Reproducible example

A minimal reproducer and a suggested patch will be uploaded in separate comments shortly after this issue is filed:

  • pixi-lock-order-repro-head-56ae6f39.zip (SHA-256 88349d63dd97303ae3e5469de227099abb32774c52bfe4d1ff9d725d85d64da4)
  • pixi-canonicalize-source-dependencies.patch (SHA-256 ba2e796f78553d026a302d50b28d88b76bd85bd36ceb0ab31be16528fe219bec)

With PIXI_BIN pointing to Pixi built from the commit above, the attached reproducer runs this sequence:

"$PIXI_BIN" update --no-install --no-config --color never --no-progress
cp pixi.lock update.lock

"$PIXI_BIN" lock --check --no-config --color never --no-progress
cp pixi.lock check.lock

git diff --no-index update.lock check.lock

"$PIXI_BIN" update --no-install --no-config --color never --no-progress
cmp update.lock pixi.lock

"$PIXI_BIN" lock --check --no-config --color never --no-progress
cmp check.lock pixi.lock

The cycle is deterministic:

pixi update       -> blob f98c24614b2b74c2fc47fd94431b5fbd1aa3d6f9, repro[05f16b0f]
pixi lock --check -> blob 5c062031887ba6ea7bb636305be99ce6d297a3be, repro[5efb8c6a]
pixi update       -> blob f98c24614b2b74c2fc47fd94431b5fbd1aa3d6f9, repro[05f16b0f]
pixi lock --check -> blob 5c062031887ba6ea7bb636305be99ce6d297a3be, repro[5efb8c6a]

No package version changes. The only substantive lockfile difference is dependency order:

   - six ==1.17.0
   - python
-  - cuda-cudart >=13.4.49,<14.0a0
   - cuda-nvrtc >=13.4.59,<14.0a0
+  - cuda-cudart >=13.4.49,<14.0a0
   - python_abi 3.14.* *_cp314

The same-name local and conda-forge six packages deliberately trigger the repeated re-solve. The resulting "required source package is locked as binary" diagnostic appears to be #6161. That problem is independent: fixing it would hide this particular trigger, but it would not make source-record generation deterministic when a re-solve occurs for another reason.

This was originally observed in CUDA Python CI; the full production evidence is in NVIDIA/cuda-python#2804.

Issue description

Equivalent source metadata is emitted in two different dependency orders. Because PackageRecord.depends is also hashed in sequence order, this changes both the serialized lockfile and the source-record identifier.

The relevant path appears to be:

Pixi's satisfiability implementation already explicitly treats depends and constrains as unordered multisets in diff_dep_sequences.

The suggested patch sorts the canonical MatchSpec strings before constructing PackageRecord, and therefore before computing the source identifier. It does not deduplicate entries. Its focused regression test fails before the fix with package_c before package_b, and passes with the fix. All 158 pixi_command_dispatcher unit tests also pass.

With an ordering-only patched binary, the reproducer's lockfile is byte-identical before and after pixi lock --check (Git blob 4b7d3c6f3fe19ed7ae57569865d23b8ce238dbf4). The command still exits nonzero because the fixture independently triggers #6161, but it no longer rewrites the lockfile.

Expected behavior

Semantically equivalent depends and constrains multisets should have a canonical serialized order and produce the same source identifier, regardless of solved-record iteration order or the command path that caused the re-solve.

pixi lock --check should never modify pixi.lock solely because those dependencies were encountered in a different order.

Activity

  1. rwgk commented on Sep 15, 2026

    @rwgk
    Author
  2. rwgk commented on Sep 15, 2026

    @rwgk
    Author
  3. rwgk commented on Sep 15, 2026

    @rwgk
    Author

    Hi pixi team, JIC you wonder: the entire issue including reproducer and suggested patch was generated by codex gpt-5.6-sol ultra. I did the general steering, but all low-level work was done by the agent.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions