fix(updates): resolve relative registry pagination URL so tag listing doesn't crash (#945)

listTags() follows the registry's Link-header pagination, but the next-page
URL is relative per the OCI/Docker registry spec (e.g.
"/v2/ollama/ollama/tags/list?last=0.9.3-rc5&n=1000"). The code assigned that
raw relative path straight back to `url` and re-fetched it, so fetch() threw
"Failed to parse URL from /v2/...". Any image repo with more than 1000 tags
paginates, so the entire tag list — and therefore the update check — failed
silently for ollama/ollama and filebrowser/filebrowser.

That's the root cause of #945 ("won't update past 0.24.0"): the Ollama
update check never completed, so no newer version was ever offered.

Resolve the next-page URL against the registry origin with
new URL(next, `https://${registry}`), which also passes absolute next-URLs
through unchanged for registries that return those.

Closes #945
This commit is contained in:
Chris Sherwood 2026-06-08 12:24:58 -07:00 committed by jakeaturner
parent da60c6ce9c
commit 5de58da4b7
No known key found for this signature in database
GPG Key ID: B1072EBDEECE328D
1 changed files with 8 additions and 2 deletions

View File

@ -139,11 +139,17 @@ export class ContainerRegistryService {
allTags.push(...data.tags)
}
// Handle pagination via Link header
// Handle pagination via Link header. Per the OCI/Docker registry spec the next-page
// URL is relative (e.g. "/v2/<repo>/tags/list?last=<tag>&n=1000"), so it must be
// resolved against the registry origin before re-fetching — assigning the raw relative
// path to `url` makes fetch() throw "Failed to parse URL". This silently broke update
// checks for any repo with >1000 tags (e.g. ollama/ollama, filebrowser/filebrowser),
// which is the root cause of #945. new URL(relative, base) also passes absolute
// next-URLs through unchanged, so it's safe for registries that return those.
const linkHeader = response.headers.get('link')
if (linkHeader) {
const match = linkHeader.match(/<([^>]+)>;\s*rel="next"/)
url = match ? match[1] : ''
url = match ? new URL(match[1], `https://${parsed.registry}`).toString() : ''
} else {
url = ''
}