Skip to content

[BUG]: For a while after a release, a bare major such as java@21-tem can install a build that vfox search does not list yet #113

Closed

Description

@linghengqian

Version
vfox-java main (b635aaa), vfox 1.0.13

OS
Linux

Describe the bug
vfox search java <distribution> asks Foojay for every package of the distribution, but a bare major asks another question: java@21-tem asks for version=21&latest=available, and java@23-mandrel for distribution_version=23:

local latest = version:match("^%d+$") and "&latest=available" or ""

vfox-java/lib/foojay.lua

Lines 281 to 282 in b635aaa

local query = version ~= "" and "&distribution_version=" .. encode(version) or ""
for _, package in ipairs(request("", query) or {}) do

local result = request(version, latest)

Foojay's answers come through Cloudflare, which caches each URL on its own, so the two questions get answers of different ages:

$ curl -sS -D - -o /dev/null 'https://api.foojay.io/disco/v3.0/packages/jdks?version=&distribution=mandrel&architecture=amd64&archive_type=tar.gz&operating_system=linux&lib_c_type=glibc&directly_downloadable=true' | grep -i -E '^(age|last-modified|cf-cache-status):'
age: 1321
last-modified: Tue, 20 Oct 2026 17:31:11 GMT
cf-cache-status: HIT
$ curl -sS -D - -o /dev/null 'https://api.foojay.io/disco/v3.0/packages/jdks?version=&distribution=mandrel&architecture=amd64&archive_type=tar.gz&operating_system=linux&lib_c_type=glibc&directly_downloadable=true&distribution_version=23' | grep -i -E '^(age|last-modified|cf-cache-status):'
age: 93
last-modified: Tue, 20 Oct 2026 17:51:40 GMT
cf-cache-status: HIT
$ curl -sS -D - -o /dev/null 'https://api.foojay.io/disco/v3.0/packages/jdks?version=&distribution=temurin&architecture=amd64&archive_type=tar.gz&operating_system=linux&lib_c_type=glibc&directly_downloadable=true' | grep -i -E '^(age|last-modified|cf-cache-status):'
age: 1341
last-modified: Tue, 20 Oct 2026 17:30:53 GMT
cf-cache-status: HIT
$ curl -sS -D - -o /dev/null 'https://api.foojay.io/disco/v3.0/packages/jdks?version=21&distribution=temurin&architecture=amd64&archive_type=tar.gz&operating_system=linux&lib_c_type=glibc&directly_downloadable=true&latest=available' | grep -i -E '^(age|last-modified|cf-cache-status):'
age: 632
last-modified: Tue, 20 Oct 2026 17:42:42 GMT
cf-cache-status: HIT

So for a while after Foojay adds a release, vfox install can take it while vfox search does not list it yet. That failed E2E on #111 on 2026-10-20, on the GraalVM Community rows of ubuntu-latest, at 16:22 UTC, minutes after Oracle GraalVM 25.0.5 reached Foojay, and again in the next run half an hour later. checkGraalVMBareMajor fakes the builds of 25 that vfox search java graal lists as installed, so that vfox install java@25-graal finds one of them, but the install took 25.0.5, which the search did not list, and downloaded it (https://github.com/version-fox/vfox-java/actions/runs/39456445454/job/118744465851, https://github.com/version-fox/vfox-java/actions/runs/39460751060/job/118759263303):

Error:      	"Preinstalling java@25.0.5-graal...\nVerifying checksum ...\nWARNING: Checksum is not provided, skip verify...\nUnpacking /root/.vfox/cache/java/graalvm-jdk-25.0.5_linux-x64_bin.tar.gz...\nInstall java@25.0.5 [...]
Test:       	TestE2E/main-graalce
Messages:   	vfox install java@25-graal must take 25.0.4.1.1-graal, the newest build that is no feature release

#111 then made Oracle GraalVM and GraalVM Community ask what the search asks. Two checks on the Temurin rows, which run on every runner, compare the search with a bare major the same way and can fail the same way: checkOwnNumbers with java@23-mandrel and java@23-nik, as Mandrel and Liberica NIK put out a 23.1 release every quarter, and checkNameOnly with the newest major of Eliya, OpenLogic and Semeru certified, which still release:

func checkNameOnly(ctx context.Context, t *testing.T, ctr tc.Container, platform string) {
t.Helper()
names := common.NameOnlyDistributions(platform)
var dirs []string
for _, name := range names {
search := "vfox search java " + name
out := execRetry(ctx, t, ctr, search, search)
spec, newest, ok := common.NewestBareMajor(common.SearchedVersions(out), name)
require.Truef(t, ok, "%s lists no newest version that a bare major names\n--- output ---\n%s", search, out)
dir := `"${VFOX_HOME:-$HOME/.vfox}"/cache/java/` + shQuote("v-"+newest)
dirs = append(dirs, dir)
execOK(ctx, t, ctr, "mkdir --parents "+dir+"/"+shQuote("java-"+newest))
out = execRetry(ctx, t, ctr, "vfox install java@"+spec, "vfox install java@"+spec)
require.Containsf(t, common.StripANSI(out), "java@"+newest+" is already installed",
"vfox install java@%s must take %s, the newest version %s lists", spec, newest, search)
}
if len(dirs) > 0 {
execOK(ctx, t, ctr, "rm --recursive "+strings.Join(dirs, " "))
}
t.Logf("PASS %d distributions go by name on %s: %s", len(names), platform, strings.Join(names, ", "))
}
// checkOwnNumbers proves Mandrel and Liberica NIK go by the GraalVM numbers
// they carry (see common.OwnNumberedDistributions): `vfox search java
// <short>` lists the release the suite names under its number, and with it
// and the newest release of its major faked as installed, `vfox install
// java@<long>-<release>` and `vfox install java@<major>-<short>` find those
// installed (see common.OwnNumberSpecs and common.NewestOfMajor), so nothing
// downloads.
func checkOwnNumbers(ctx context.Context, t *testing.T, ctr tc.Container, platform string) {
t.Helper()
names := common.OwnNumberedDistributions(platform)
for _, name := range names {
search := "vfox search java " + name
out := execRetry(ctx, t, ctr, search, search)
searched := common.SearchedVersions(out)
spec, installed, bare := common.OwnNumberSpecs(name)
require.Containsf(t, searched, installed, "%s must list %s\n--- output ---\n%s", search, installed, out)
newest, ok := common.NewestOfMajor(searched, bare)
require.Truef(t, ok, "%s lists no release that %s names\n--- output ---\n%s", search, bare, out)
var dirs []string
for _, version := range []string{installed, newest} {
dir := `"${VFOX_HOME:-$HOME/.vfox}"/cache/java/` + shQuote("v-"+version)
dirs = append(dirs, dir)
execOK(ctx, t, ctr, "mkdir --parents "+dir+"/"+shQuote("java-"+version))
}
for _, c := range []struct{ spec, want string }{{spec, installed}, {bare, newest}} {
out = execRetry(ctx, t, ctr, "vfox install java@"+c.spec, "vfox install java@"+c.spec)
require.Containsf(t, common.StripANSI(out), "java@"+c.want+" is already installed",
"vfox install java@%s must take %s, which %s lists", c.spec, c.want, search)
}
execOK(ctx, t, ctr, "rm --recursive "+strings.Join(dirs, " "))
t.Logf("PASS java@%s takes %s and java@%s %s", spec, installed, bare, newest)
}
}

My guess is that a bare major should ask for every package, as the search does, and take the newest release of the major itself, as #111 does for GraalVM. I compared that with latest=available for every bare major of the other 27 distributions on Foojay, on Linux x64 and arm64, Linux x64 with musl, macOS x64 and arm64 and Windows x64 and arm64, and got the same release everywhere. Only Dragonwell 11 on Windows x64 and Linux x64 with musl changes file, from the Standard to the Extended build of 11.0.32, which java@11.0.32-albba already installs.

Found while working on #105.

Activity

  1. linghengqian commented on Oct 20, 2026

    @linghengqian
    MemberAuthor

    I am working on the current issue.

  2. self-assigned this
    on Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions