The update-prerelease-reference workflow on quarto-web can pick a stale quarto-cli prerelease version and regenerate the reference docs from it, because the version resolution has no check that the version it found is actually the newest.
What happened
On 2026-08-17, between roughly 13:19 and 16:26 UTC, the GitHub Releases API served inconsistent paginated results to the update-downloads cron job (runs every 15 min). The "latest prerelease" version it resolved bounced across consecutive runs:
13:19 1.11.1 (correct)
13:47 1.2.113
14:28 0.2.434 (a "Daily" build)
14:43 1.9.10 <- this run opened quarto-dev/quarto-web#2146
14:57 1.5.49
15:26 1.11.1 (back to correct, stable since)
The 14:43 run landed on v1.9.10 (published 2025-11-06, ten months stale) and, since it found a valid release with assets, went ahead and cloned quarto-cli at that tag and opened a PR regenerating 63 reference files against it. A later run the same day, back on the correct v1.11.1, confirmed the prerelease branch was already current:
No changes detected - reference pages are already up to date for v1.11.1
I closed quarto-dev/quarto-web#2146 without merging, since it would have reverted the reference docs to the v1.9.10 state.
Where this comes from
The version comes from getPrerelease(), which pages through listReleases and takes the first release flagged prerelease: true, with no comparison against the previously resolved version or the release's semver position:
source
const getPrerelease = async () => {
// List the releases
var pagenumber = 1;
var matchedRelease = undefined;
while(true) {
console.log("page " + pagenumber + " of prereleases");
var releases = await octokit.rest.repos.listReleases({
owner,
repo,
per_page: 25,
page: pagenumber
});
for (const release of releases.data) {
if (release.prerelease) {
matchedRelease = release;
break;
}
}
if (matchedRelease) {
break;
} else {
pagenumber = pagenumber + 1;
}
}
return matchedRelease;
}
The only validation downstream is that the matched release has assets, which an old prerelease still has, so it passes silently.
Suggestion
We could add a sanity check before accepting the resolved prerelease, for example rejecting a candidate whose semver is lower than the currently committed docs/download/_prerelease.json version, or than the latest stable release. That would have caught all six bad values in the table above without needing the API to behave.
Related: quarto-dev/quarto-web#2146
The
update-prerelease-referenceworkflow on quarto-web can pick a stale quarto-cli prerelease version and regenerate the reference docs from it, because the version resolution has no check that the version it found is actually the newest.What happened
On 2026-08-17, between roughly 13:19 and 16:26 UTC, the GitHub Releases API served inconsistent paginated results to the
update-downloadscron job (runs every 15 min). The "latest prerelease" version it resolved bounced across consecutive runs:The 14:43 run landed on v1.9.10 (published 2025-11-06, ten months stale) and, since it found a valid release with assets, went ahead and cloned quarto-cli at that tag and opened a PR regenerating 63 reference files against it. A later run the same day, back on the correct v1.11.1, confirmed the
prereleasebranch was already current:I closed quarto-dev/quarto-web#2146 without merging, since it would have reverted the reference docs to the v1.9.10 state.
Where this comes from
The version comes from
getPrerelease(), which pages throughlistReleasesand takes the first release flaggedprerelease: true, with no comparison against the previously resolved version or the release's semver position:source
The only validation downstream is that the matched release has assets, which an old prerelease still has, so it passes silently.
Suggestion
We could add a sanity check before accepting the resolved prerelease, for example rejecting a candidate whose semver is lower than the currently committed
docs/download/_prerelease.jsonversion, or than the latest stable release. That would have caught all six bad values in the table above without needing the API to behave.Related: quarto-dev/quarto-web#2146