leanprover / leanprover/lean4

lake cache get fails a whole batch after one transient network failure

Open
#14,739 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Lean
Stars
9.2k
Forks
990
Avg merge
1d 17h
Merged PRs (30d)
175

Description

Description

lake cache get and lake cache put transfer a batch of artifacts with one curl invocation. When one transfer fails in a transient way, the whole batch fails. Lake does not retry the failed transfer.

curl --retry does not prevent this. It retries only timeouts and a fixed set of response codes (408, 429, 500, 502, 503, 504). It does not retry a connection that drops mid-body. It also cannot detect a corrupted body: when the response has no Content-Length, a stream that ends early looks like a complete transfer. Only Lake's content hash check can catch that case.

Context

Mathlib runs a daily CI job that exercises Lake's artifact cache against a remote bucket. The job downloads the full cache (~8300 artifacts) with lake cache get. One dropped connection failed the whole job (log).

Steps to Reproduce

The mock cache server in tests/lake/tests/cacheTransfer/server.py reproduces the failure classes deterministically. The steps below use its reset fault mode, which drops every request without a response.

# Start the mock server; it writes its port to a file when it is ready
python3 tests/lake/tests/cacheTransfer/server.py \
  --store /tmp/store --port-file /tmp/port > /tmp/server.log 2>&1 &
sleep 1
URL="http://127.0.0.1:$(cat /tmp/port)"

# A minimal workspace and a mappings file that names one artifact
mkdir -p /tmp/repro && cd /tmp/repro
printf 'name = "repro"\n' > lakefile.toml
printf '"2026-03-17"\n["aaaaaaaaaaaaaaaa","0123456789abcdef.ltar"]\n' > outputs.jsonl

# Fetch the batch through the fault mode
LAKE_CACHE_DIR=.lake/cache \
LAKE_CACHE_ARTIFACT_ENDPOINT="$URL/reset/a0" \
LAKE_CACHE_REVISION_ENDPOINT="$URL/reset/r0" \
lake cache get outputs.jsonl --scope=repro
echo "exit: $?"

# Count the requests that Lake made for the artifact
grep -c 'GET /reset' /tmp/server.log

Expected behavior: Lake retries a transfer that fails in a transient way, and the request count is greater than 1. The batch succeeds when a retry succeeds; this fault is persistent, so the batch fails after the retries. A failure that a retry cannot fix, such as a 404, fails the batch immediately.

Actual behavior: The request count is 1. Lake makes one attempt, the batch fails, and lake cache get exits with code 1:

error: repro: failed to download artifact 0123456789abcdef (status code: 0)
  curl error: Empty reply from server
  local path: .lake/cache/artifacts/0123456789abcdef.ltar
  remote URL: http://127.0.0.1:53646/reset/a0/repro/0123456789abcdef.art
error: repro: failed to download some artifacts
error: repro: curl exited with code 52
exit: 1
requests: 1
Versions

Observed with leanprover/lean4:v4.33.0-rc1 on Linux (ubuntu-latest GitHub runners).
Reproduced on current master (7c90644a5f) on macOS (Darwin 25.4.0, arm64). On master, #14651 reports the failure cleanly, but the batch still fails.

Additional Information

Forensics on the failed CI run

  • Two of 8309 downloads failed, 10 ms apart. Both failures are consistent with one dropped connection that carried several multiplexed HTTP/2 streams.
  • The artifact bytes in the bucket were correct. They were byte-identical to the uploaded staging files, and all 8309 staged files hash to their names.
  • The reported mismatch hash (aab4dd01e694a7f6) is the Lake hash of exactly the first 131072 bytes (128 KiB) of the correct artifact. The stream died mid-body, at a clean buffer boundary.
  • The second artifact failed with no such file or directory: its stream died before the first body byte, so curl wrote no output file.
Impact

A CI job that downloads a full cache fails when any single transfer breaks. The data at rest is intact, so a manual rerun succeeds. The failure rate grows with the batch size.

Add 👍 to issues you consider important. If others are impacted by this issue, please ask them to add 👍 to it.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with tests/lake/tests/cacheTransfer/server.py and run its reset fault-mode reproduction to confirm the single-request failure. Then locate the Lake cache transfer entry point and its existing tests; done means transient transfer failures are retried, successful retries allow the batch to finish, and persistent or non-retryable failures still fail as expected.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
build-system
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.