Skip to content

ci: fix corrupted distributions when merging parallel build artifacts - #514

Draft
bhimrazy wants to merge 3 commits into
Lightning-AI:mainfrom
bhimrazy:ci/fix-artifact-merge-corruption
Draft

ci: fix corrupted distributions when merging parallel build artifacts#514
bhimrazy wants to merge 3 commits into
Lightning-AI:mainfrom
bhimrazy:ci/fix-artifact-merge-corruption

Conversation

@bhimrazy

Copy link
Copy Markdown
Collaborator

What does this PR do?

Fixes the flaky check-package-extras / pkg-check failure that shows up on most PRs and goes away on re-run.

The merge-artifacts job downloads every *-build-* artifact with merge-multiple: true into a single dist/ folder. When the build matrix has more than one OS, each build job produces identically named files (this package is py3-none-any, so all builds emit the same sdist/wheel names). download-artifact extracts them concurrently onto the same paths, the writes interleave, and the result is a corrupted archive.

That is why only check-package-extras fails: it is the only caller with a two-OS build matrix. check-package, which uses the same workflow with a single build OS, never fails.

Evidence

The artifacts from run 28387440212 are still downloadable, so this can be checked directly:

artifact lightning_utilities-0.15.3.tar.gz gzip -t
…-build-0 6dc1de8c… (33560 B) ok
…-build-1 0c3c2665… (33553 B) ok
merged 65bbf534… (33560 B) invalid compressed data--crc error

Each build artifact is individually intact; the merged one matches neither and is corrupt. Enumerating it stops after 30 members and src/lightning_utilities/install/requirements.py is missing — exactly what pip reported:

FileNotFoundError: .../src/lightning_utilities/install/requirements.py
ERROR: Failed to build lightning_utilities-0.15.3.tar.gz when getting requirements to build wheel

The wheel in that same merged artifact is byte-identical to build-1, i.e. one file won its race cleanly while the other was shredded.

Changes

1. Do not extract multiple artifacts into one folder. Drop merge-multiple: true so each lands in its own sub-folder, then flatten sequentially, keeping the first of any duplicate name and logging the ones dropped. Files with distinct names (e.g. real platform-specific wheels) are all preserved.

2. Actually verify archive integrity. twine check passed on the corrupted tarball above — it stops at the first unreadable tar header and treats it as end-of-archive, so it validated the intact prefix and never reached the gzip CRC. Added a full decompress of any sdist and a testzip() of any wheel.

Testing

The shell logic was exercised locally against the real artifacts downloaded from the failing run:

  • two-build merge → both files intact, hashes match build-0, duplicates logged
  • the corrupted merged tarball → correctly rejected
  • wheel-only consumer (no sdist) → no false failure
  • single-build consumer → unchanged
  • platform-specific wheels with distinct names → all preserved
  • empty dist/ → still fails loudly

Note this is a reusable workflow, so the second change had to stay safe for callers that do not produce an sdist.

Notes

  • Only the workflow is touched; no package code changes.
  • Trimming check-package-extras to a single build OS in ci-use-checks.yaml would remove the duplicate at the source and save some CI time. Deliberately not done here: it would only fix this repo and leave the same hazard for any other caller of this reusable workflow that uses a multi-OS build matrix. Happy to add it as a follow-up.
  • The bad checksum variant seen in run 28387450718, where twine check did fail, is consistent with the same cause at a different corruption offset, but that run died before uploading a merged artifact so it could not be byte-verified.

The `merge-artifacts` job downloaded every `*-build-*` artifact with
`merge-multiple: true` into a single `dist/` folder. Build jobs running on
several OSes produce identically named files for a platform-independent
package, so the artifacts were extracted concurrently onto the same paths and
the writes interleaved, yielding a corrupted archive.

This surfaced as a flaky `check-package-extras / pkg-check` failure that passed
on re-run, since whether the interleaving damaged the payload was a race:

    FileNotFoundError: .../src/lightning_utilities/install/requirements.py
    ERROR: Failed to build lightning_utilities-0.15.3.tar.gz

Download each artifact into its own sub-folder instead and flatten them
sequentially, keeping the first of any duplicate name and reporting the rest.

`twine check` did not catch this: it stops at the first unreadable tar header
and treats it as end-of-archive, so it validated the intact prefix and never
reached the gzip CRC. Verify the archives end to end as well.
@codecov-commenter

codecov-commenter commented Aug 17, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@ad6aff6). Learn more about missing BASE report.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@          Coverage Diff          @@
##             main   #514   +/-   ##
=====================================
  Coverage        ?    72%           
=====================================
  Files           ?     17           
  Lines           ?    749           
  Branches        ?      0           
=====================================
  Hits            ?    540           
  Misses          ?    209           
  Partials        ?      0           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

`download-artifact` only places each artifact in its own sub-folder when the
pattern resolves to more than one; a lone artifact is extracted directly into
the path. Globbing `dist-parts/*/*` therefore found nothing for single-build
callers such as `check-package`, leaving `dist/` empty and failing on an opaque
`twine check: error: the following arguments are required: dist`.

Collect files at any depth so both layouts work, and fail with an explicit
message when no distribution is found at all.
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.

2 participants