Skip to content

fix(build): fall back to a mirror when ffmpeg.org refuses the runner - #226

Merged
EtienneLescot merged 1 commit into
release/v1.8.0from
fix/ffmpeg-fetch-retry
Aug 1, 2026
Merged

fix(build): fall back to a mirror when ffmpeg.org refuses the runner#226
EtienneLescot merged 1 commit into
release/v1.8.0from
fix/ffmpeg-fetch-retry

Conversation

@EtienneLescot

@EtienneLescot EtienneLescot commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

The macOS x64 leg of the v1.8.0-rc.6 build dies on the ffmpeg tarball fetch:

curl: (35) Recv failure: Connection reset by peer

This is an egress-level block, not congestion and not a bad pin. The evidence is in the two attempts of that run:

attempt 1 attempt 2
arm64 leg (macos-latest) success success
x64 leg (macos-15-intel) reset after ~1s reset after ~1s

Both legs had the same cold cache and fetched the same tarball from the same host. One pool works, the other is reset immediately, and it reproduces twenty minutes apart. Retrying does not clear that — an earlier version of this PR added --retry-all-errors alone and would not have fixed the build.

The pin itself is fine: ffmpeg.org serves bytes matching TARBALL_SHA256 exactly, verified locally.

The fix

A second source. Debian's .orig.tar.xz is the upstream tarball unmodified — verified byte-identical to the pinned sha256 — and deb.debian.org is CDN-backed:

const TARBALL_URLS = [
  `https://ffmpeg.org/releases/ffmpeg-${VERSION}.tar.xz`,
  `https://deb.debian.org/debian/pool/main/f/ffmpeg/ffmpeg_${VERSION}.orig.tar.xz`,
];

Each source must both download and match the checksum before it is used. The checksum is what makes trusting a second origin safe, and it gates every source equally — nothing is downgraded. ffmpeg.org stays first, and a mirror that does not yet carry a future version is skipped rather than fatal.

Three flags carry their own reasons, none of them decoration:

  • --retry-all-errors — curl only auto-retries what it classes as transient (timeouts, 429, 5xx). That does not include a connection reset or a TLS handshake failure, which are exactly the errors here. --retry 3 alone is the obvious-looking fix and would have done nothing.
  • --connect-timeout 20 — a throttled origin hangs rather than refuses. Measured: after a few rapid fetches, ffmpeg.org left a connect sitting for 75 seconds before failing. Times four attempts, that is five minutes of build time burned before the second source is even tried.
  • -f — keeps an HTTP error page from being written to the tarball and resurfacing as a checksum mismatch, which reads like a moved pin rather than a bad response.

Related issue

None — found from the rc.6 build failure.

Type of change

  • Bug fix
  • Feature
  • Enhancement
  • Documentation
  • Refactor / maintenance
  • Performance
  • Security

Release impact

  • Patch
  • Minor
  • Major / breaking change
  • No release note needed

CI reliability only; nothing in the shipped app changes. This is what unblocks a macOS releasepublish-release needs build-macos, so rc.6 has not published.

Desktop impact

  • Windows
  • macOS
  • Linux
  • Installer / packaging
  • Not platform-specific

Screenshots / video

n/a — build script.

Testing

downloadTarball was extracted from the file and run against real endpoints, so this exercises the shipped code rather than a retelling of it:

scenario result
canonical source reachable downloads, checksum OK
canonical dead → Debian falls through, checksum OK
canonical serves wrong bytes (ffmpeg 8.1.1) rejected on checksum, next source used
every source broken throws, listing each attempt with its reason

The failure message from the last case:

Could not obtain ffmpeg 8.1.2 from any source.
Expected sha256 464beb5e7bf0c311e68b45ae2f04e9cc2af88851abb4082231742a74d97b524c
  https://127.0.0.1:9/nope.tar.xz
    curl exited with 7
  https://ffmpeg.org/releases/ffmpeg-8.1.1.tar.xz
    checksum b6863adde98898f42602017462871b5f6333e65aec803fdd7a6308639c52edf3

Retry behaviour verified separately, against a refused connection — the same class of failure as a reset:

curl -fsS --retry 2 --retry-delay 1                     → exit 7 after 0s   (no retry)
curl -fsS --retry 2 --retry-delay 1 --retry-all-errors  → exit 7 after 2s   (two retries)

Also: --retry-all-errors needs curl ≥ 7.71 (2020) and macOS runners ship 8.x; node --check and biome check clean.

Not tested: the script end to end, which builds ffmpeg from source (~5 min) and writes into crates/thirdparty/. The change is confined to how the tarball is obtained; everything downstream of the checksum is untouched. The x64 leg of the next macOS build is the real proof — and it is the case that currently fails, so it will be obvious either way.

Out of scope

scripts/fetch-ffmpeg.mjs:359 has the same single-source shape (await fetch(url), no retry) but is deliberately left alone: it is the Windows/Linux path, pulls from GitHub releases rather than ffmpeg.org, and would need a different fix since it uses node's fetch. Worth a follow-up if that path ever flakes — though GitHub is not the origin causing trouble here.

If the block turns out to be permanent rather than a reputation-based throttle, the sturdier move is to stop depending on a third-party origin at build time at all: publish the pinned tarball as an asset on an internal release, the way stage-whisper-stt.sh already does for the whisper binaries. That is a bigger change and this one is enough to unblock the release.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f7c234aa-ba30-4d99-8c8b-83ac893bf600

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

The macOS x64 leg of v1.8.0-rc.6 died on the ffmpeg tarball fetch, twice,
twenty minutes apart:

    curl: (35) Recv failure: Connection reset by peer

This is not congestion and not a bad pin. In both runs the arm64 leg on
`macos-latest` fetched the same tarball from the same host with the same cold
cache and succeeded, while the x64 leg on `macos-15-intel` was reset about a
second after starting. An immediate reset that reproduces on one runner pool
and never on the other is an egress-level block, so no amount of retrying
clears it — a first attempt at this shipped only `--retry-all-errors` and would
not have fixed the build.

So the source list grows a second entry. Debian's `.orig.tar.xz` is the upstream
tarball unmodified — verified byte-identical to the pinned sha256 — and
deb.debian.org is CDN-backed. Each source is tried in turn and must both
download and match the checksum; the checksum is what makes a second origin safe
to trust, and it gates every source equally. Nothing is downgraded: ffmpeg.org
stays first, and a mirror that lacks a future version is skipped rather than
fatal.

Three flags carry their own reasons:

- `--retry-all-errors`, because curl only auto-retries what it classes as
  transient (timeouts, 429, 5xx) — not a reset, not a handshake failure, which
  are exactly the errors seen here. Verified against a refused connection:
  `--retry 2 --retry-delay 1` gives up after 0s, adding `--retry-all-errors`
  spends 2s retrying.
- `--connect-timeout 20`, because a throttled origin hangs rather than refuses.
  Measured: after a few rapid fetches ffmpeg.org left a connect sitting for 75s
  before failing. Times four attempts, that is five minutes burned before the
  second source is even tried.
- `-f`, so an HTTP error page is not written to the tarball and resurfaced as a
  checksum mismatch, which reads like a moved pin rather than a bad response.

Exercised by extracting the function and running it against real endpoints:
canonical alone succeeds; a dead first source falls through to Debian; a source
serving the wrong bytes (ffmpeg 8.1.1) is rejected on checksum and the next one
is used; and with every source broken it throws listing each attempt with its
reason — curl status or the actual hash.

The sibling `scripts/fetch-ffmpeg.mjs` has the same single-source shape at line
359 but is left alone: it is the Windows/Linux path, pulls from GitHub releases
rather than ffmpeg.org, and uses node's fetch rather than curl.
@EtienneLescot
EtienneLescot force-pushed the fix/ffmpeg-fetch-retry branch from 3d35453 to c1d204f Compare August 1, 2026 14:59
@EtienneLescot EtienneLescot changed the title fix(build): retry the ffmpeg tarball fetch instead of losing the whole macOS job fix(build): fall back to a mirror when ffmpeg.org refuses the runner Aug 1, 2026
@EtienneLescot
EtienneLescot merged commit a051e50 into release/v1.8.0 Aug 1, 2026
13 checks passed
@EtienneLescot
EtienneLescot deleted the fix/ffmpeg-fetch-retry branch August 1, 2026 15:16
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.

1 participant