#4394·mamba

[libmamba] Per-package repodata `url`/`urls` are discarded: `set_solvables_url` overwrites every solvable's URL with the channel-derived one

Author: sunnyyangyangyangCreated Sep 1, 2026Updated Sep 1, 2026

Summary

Packages whose files are not located at <channel>/<subdir>/<filename> (e.g. hosted as GitHub Release assets because the files exceed git's 100 MB limit, or on any off-channel storage advertised via the standard repodata urls field) cannot be installed by mamba/micromamba: libmamba always re-derives the download URL from the channel base URL and fails with 404, while classic conda honors urls and works with the same channel.

This is not merely a key-name gap; there are two independent problems:

Problem 1: only the singular url key is parsed

  • libmamba/src/specs/package_info.cpp, PackageInfo::from_json (tag 2.4.0; unchanged on main as of 2026-09-01):

    pkg.package_url = j.value("url", "");

    No fallback to the standard urls list anywhere (grep for "urls" in libmamba/src + libmamba/include: zero hits).

Problem 2 (the blocker): set_solvables_url unconditionally overwrites per-package URLs

Even when url is present in repodata and stored on the solvable by set_solvable (solv.set_url(pkg.package_url) in solver/libsolv/helpers.cpp), solver/libsolv/database.cpp calls, right after loading the repo:

  set_solvables_url(p_repo, std::string(url), channel_id);

and set_solvables_url (helpers.cpp) then rewrites the URL of every solvable to repo_url / file_name:

  s.set_url((url / s.file_name()).str(specs::CondaURL::Credentials::Show));

with the comment "The solvable url, this is not set in libsolv parsing so we set it manually". The per-package value set earlier is destroyed (per the adjacent comment it isn't even readable at that point). Consequently make_package_info materializes package_url = s.url() = <channel>/<subdir>/<filename>, Transaction considers it non-empty (so the url_for_channel_platform fallback never fires), and the fetcher 404s on the channel.

Reproduction

  1. Channel https://sunnyyangyangyang.github.io/ninfer-feedstock: repodata on GitHub Pages; .conda files as GitHub Release assets. Entries carry both urls and url keys pointing at the release assets (verified byte-for-byte in the repodata file libmamba itself fetched and cached, ~/.mamba/pkgs/cache/23f452bb.json).

  2. mamba install -p <prefix> ninfer (mamba 2.4.0, Fedora 44 RPM; same code on current main)

  3. libmamba downloads <channel>/linux-64/<filename>.conda (does not exist) instead of the repodata-advertised URL:

    error    libmamba Failed to download package from https://sunnyyangyangyang.github.io/ninfer-feedstock/linux-64/ninfer-...conda (status 404)
    
  4. The identical channel works with classic conda. Installing the same package by direct URL (mamba install <release-asset-url>) works with mamba, confirming the channel-derived re-derivation is the failing step.

Suggested fix

In set_solvables_url, only set the channel-derived URL when the solvable has no per-package URL (i.e. make the overwrite conditional on the previously internalized package_url being empty), and in PackageInfo::from_json fall back to urls[0] when url is absent:

pkg.package_url = j.value("url", "");
if (pkg.package_url.empty()) {
    if (auto u = j.find("urls"); u != j.end() && u->is_array() && !u->empty())
        pkg.package_url = u->at(0).get<std::string>();
}

Environment

  • mamba 2.4.0 (Fedora 44 RPM mamba-2.4.0-3.fc44.x86_64); micromamba affected (shared libmamba)
  • Verified against main branch sources