From 5de58da4b7f25843e4be59504f9631291318957b Mon Sep 17 00:00:00 2001 From: Chris Sherwood Date: Mon, 8 Jun 2026 12:24:58 -0700 Subject: [PATCH] fix(updates): resolve relative registry pagination URL so tag listing doesn't crash (#945) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- admin/app/services/container_registry_service.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/admin/app/services/container_registry_service.ts b/admin/app/services/container_registry_service.ts index afdd39d..2fc465d 100644 --- a/admin/app/services/container_registry_service.ts +++ b/admin/app/services/container_registry_service.ts @@ -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//tags/list?last=&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 = '' }