Container registry: multi-arch tags 500 on the legacy (non-database) path since 19.0.2
### Summary Since GitLab 19.0.2, the container registry UI and tag API return 500 for multi-arch tags when the registry runs on the legacy (non-database) path (`database.enabled = false`, or prefer-fallback mode). The UI shows "This image has no active tags" and "Something went wrong while fetching the repository list". The tag API (`GET /projects/:id/registry/repositories/:rid/tags/:tag`) returns 500. `docker push` and `pull` are unaffected. This is a Rails-side regression, separate from the registry prefer-mode bug fixed in 19.0.2 (container-registry v4.40.1, gitlab-org/container-registry!2877+s). It surfaced in gitlab-org/gitlab#600955+s. ### Root cause The shared `ACCEPTED_TYPES` in `lib/container_registry/base_client.rb` gained `manifest.list.v2+json` and `oci.image.index.v1+json`, and lost the separate `ACCEPTED_TYPES_RAW`, in gitlab-org/gitlab!238384+s. `ACCEPTED_TYPES` is also the Accept header for the default `faraday` connection (`base_client.rb:119`), which the legacy path uses for every per-tag manifest fetch (`repository_manifest`, `repository_tag_digest`), not only Geo's `faraday_raw`. The wider Accept changes what the registry returns for a multi-arch tag: - **Docker manifest list:** the registry previously downgraded it to a single-platform schema2 manifest (`rewriteManifestList`, via the registry's asymmetric Accept negotiation), which the client parsed. It now returns the real fat manifest. `configure_connection` does not register `manifest.list.v2+json` as a JSON response type, so the body returns as an unparsed String and `ContainerRegistry::Tag#layers` runs `(manifest['layers'] || manifest['fsLayers']).map`, i.e. `nil.map` -> `NoMethodError` -> 500. It is reached through `total_size` and the GraphQL `totalSize` field. - **OCI image index:** previously returned 404 (ManifestUnknown) and the tag was treated as having no manifest. It now parses to a Hash with no `layers`, hitting the same `nil.map`. ### Scope 19.0.2+ installs on the legacy v2 enumeration path with multi-arch images: - `database.enabled = false` (the documented workaround for gitlab-org/gitlab#600955+s). - prefer-fallback installs (filesystem metadata, not yet imported): the v4.40.1 fix routes these to the v2 path, so they hit this too. Metadata-database installs are unaffected. The v1 `GitlabApiClient` returns tag size and digest from the API and never fetches or parses manifests (`container_repository.rb:347,364`). ### Proposed fix Give `faraday_raw` its own wide Accept again (restore `ACCEPTED_TYPES_RAW`) and keep the default `faraday` connection image-only. This preserves the Geo OCI-index fix and lets the registry keep downgrading manifest lists to a single-platform manifest on the legacy path, which is the intended v2-by-tag behavior. Fully parsing lists and indexes in the legacy client is not worth it: a real size needs per-platform manifest fan-out, the slow enumeration the database API already replaces, on a path being retired. Independent hardening: `Tag#layers` should guard against a nil or unexpected manifest (return `[]`) so a single odd tag cannot 500 the whole GraphQL query. ### Steps to reproduce 1. GitLab 19.0.2+ with the container registry on the legacy path (`registry['database']['enabled'] = false`, or prefer-fallback with filesystem metadata). 2. Push a multi-arch image, e.g. `docker buildx build --platform linux/amd64,linux/arm64 --push <ref>`. 3. Open the project container registry, or call `GET /projects/:id/registry/repositories/:rid/tags/:tag`. 4. Result: 500 and an empty tag list. ### Related - gitlab-org/gitlab#600955+s (the prefer-mode bug, this regression surfaced in its thread) - gitlab-org/gitlab!238384+s (the change that introduced this) - gitlab-org/gitlab!236905+s (its origin on `master`)
issue