Package and RPM Database RepairLesson 3 of 3
Repositories, dnf failures and rolling back
Diagnose repository, metadata, GPG and dependency errors, build a local repository, and undo or redo a transaction.
dnf repolistdnf repoquerydnf clean alldnf makecachednf historydnf history undodnf distro-syncdnf checkdnf config-managerdnf downloadcreaterepo_cdnf needs-restartingdnf versionlock
After this lesson you can
- Read a repository definition and test each of its settings from the command line.
- Map the common dnf error messages to a cause: URL, metadata, GPG, dependency, space, lock.
- Create a local repository, install from it, and use dnf history to inspect and undo a transaction.
The idea
dnf is a resolver sitting on top of repositories and rpm. A repository is a directory of .rpm files plus a repodata/ directory describing them (names, versions, dependencies, checksums). dnf downloads that description (the metadata), works out which packages satisfy your request, downloads them, checks their signatures, and hands them to rpm as a single transaction.
Three layers can fail, and error messages belong to one of them:
1 Reaching the repository URL, DNS, network, TLS, mounting a source "Cannot download repomd.xml"
2 Trusting what it says metadata checksum, GPG signature, subscription "GPG check FAILED", "Public key ... not installed"
3 Satisfying the request dependencies, conflicts, disk space, scriptlets "nothing provides", "conflicts with", "Insufficient space"
Fix in that order. A dependency error is meaningless while the metadata cannot be downloaded.
A repository definition
[labrepo]
name=Lab repository
baseurl=file:///srv/repo
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-lab
| Setting | Meaning |
|---|---|
[labrepo] | Repository id, used in --enablerepo/--disablerepo |
baseurl / metalink / mirrorlist | Where the repository is. baseurl may be http://, https://, ftp:// or file:// |
enabled | 1 uses it, 0 ignores it unless asked for |
gpgcheck | Verify package signatures |
repo_gpgcheck | Verify the signature of the metadata too |
gpgkey | Where the public key is |
sslverify, sslclientcert, sslclientkey | TLS settings; Red Hat’s CDN uses a client certificate from the subscription |
priority, exclude, includepkgs | Prefer or limit what a repository provides |
RHEL repositories are enabled by a subscription (registration with subscription-manager) and recorded in /etc/yum.repos.d/redhat.repo. On an unregistered system, that file is empty and dnf finds nothing; the fix is to register, or to use local repositories.
The repository tools
dnf repolist [--all] # enabled (or all) repositories
dnf repoinfo REPOID # details for one
dnf makecache # download metadata now (shows errors clearly)
dnf clean all # drop caches: fixes stale or corrupt metadata
dnf provides /usr/bin/foo # which package provides this file or capability
dnf repoquery --whatprovides foo.so.1 # same, from repository metadata
dnf repoquery --whatrequires PKG # who depends on PKG
dnf download PKG # fetch the .rpm only
Making a local repository
Anything that reads a directory can be a repository. Create the metadata with createrepo_c:
sudo dnf install -y createrepo_c
sudo mkdir -p /srv/repo
sudo cp *.rpm /srv/repo/
sudo createrepo_c /srv/repo # writes /srv/repo/repodata/
ls /srv/repo/repodata
repomd.xml <hash>-filelists.xml.gz <hash>-primary.xml.gz <hash>-other.xml.gz
repomd.xml is the index of the others: if it is missing, the repository does not exist as far as dnf is concerned. After adding packages, run createrepo_c --update /srv/repo. For a signed repository, sign the packages with rpmsign and publish the key.
What the errors mean
| Message (abridged) | Layer | Cause | Fix |
|---|---|---|---|
Failed to download metadata for repo 'x', Cannot prepare internal mirrorlist, Could not resolve host | 1 | URL, DNS or network | Test the URL with curl -I; fix baseurl |
Status code: 404 for .../repomd.xml | 1 | Wrong path, or no repodata/ | createrepo_c; check the directory |
Curl error (60): SSL certificate problem | 1 | Untrusted or expired certificate | Install the CA; fix the clock (timedatectl) |
Repository 'x' is missing name in configuration | 1 | Syntax in .repo file | Add name= |
Metadata file does not match checksum | 2 | Stale cache or mirror out of sync | dnf clean all, makecache |
Public key for x.rpm is not installed | 2 | Key not imported | rpm --import the right key |
GPG check FAILED | 2 | Package altered or signed with another key | Do not install; obtain it again from a trusted source |
nothing provides X needed by Y | 3 | Dependency in a repo that is disabled or not present | Find with dnf provides X; enable that repo |
package A conflicts with B | 3 | Two packages that cannot coexist | Remove one, or choose --allowerasing knowingly |
Insufficient space in download directory | 3 | /var is full | df -h /var, dnf clean all, free space |
Transaction failed: Rpm transaction failed | 3 | A scriptlet failed or a file conflicts | Read the rpm lines above it; rpm -q --scripts |
Error: Failed to ... waiting for process with pid N to finish | Another dnf is running | Wait. ps -p N; remove nothing |
Try it
Seeing the failure properly
sudo dnf clean all
sudo dnf -v makecache
Cannot download repomd.xml: Cannot download repodata/repomd.xml: All mirrors were tried
Error: Failed to download metadata for repo 'labrepo': Cannot download repomd.xml: Cannot download repodata/repomd.xml: All mirrors were tried
That is layer 1: either baseurl is wrong or repodata/ is missing. Check the first, then the second:
grep baseurl /etc/yum.repos.d/labrepo.repo
ls /srv/repo/repodata/repomd.xml
Transactions and history
Every dnf install, update and remove is a numbered transaction in /var/lib/dnf/history.sqlite.
sudo dnf history
sudo dnf history info 12
ID | Command line | Date and time | Action(s) | Altered
-------------------------------------------------------------------------------
14 | install -y tree | 2026-11-04 12:10 | Install | 1
13 | update | 2026-11-04 09:02 | Upgrade | 18
12 | install createrepo_c | 2026-11-03 17:44 | Install | 3
dnf history info ID lists the exact packages, versions and the user. You can reverse or repeat a transaction:
sudo dnf history undo 14 # reverse transaction 14
sudo dnf history redo 14 # repeat it
sudo dnf history rollback 12 # return the package set to its state after transaction 12
undo works when the previous versions are still available in an enabled repository; a downgrade of core packages (glibc, systemd) is risky and may be unsupported. After a bad update the safer paths are, in order: dnf history undo for a single transaction, dnf downgrade PKG-VERSION, dnf distro-sync (make everything match the enabled repositories exactly), and a snapshot or backup restore.
Checking afterwards
sudo dnf check
sudo dnf needs-restarting -r
dnf check verifies the dependency state of the installed set and prints nothing when it is consistent. dnf needs-restarting -r says whether a reboot is needed (a new kernel, glibc, systemd), and -s lists services that should be restarted.
Going further
Controlling updates. dnf versionlock add PKG (package python3-dnf-plugin-versionlock) pins a version; exclude=PKG* in a repository or /etc/dnf/dnf.conf skips it. dnf update --security applies only security errata. Beyond the exam: Red Hat Satellite or a local mirror (reposync) is how production fleets control what each machine sees.
Practice
0 of 3 done
Do these on your own system. They get harder. Check each result, then tick it off.
- Warm-up
Read a repository definition
List the enabled repositories. For one of them, print its definition and answer: what is the
baseurlormetalink, isgpgcheckon, is itenabled, and what dosslverifyandsslclientcert(if present) refer to?Check your result
dnf repolistlists the repo ids.dnf repoinfo REPOID(orgrep -A12 '^\[REPOID\]' /etc/yum.repos.d/*.repo) shows the settings.- You can say which file defines it (
grep -l REPOID /etc/yum.repos.d/*.repo).
Hint
Repository files are in
/etc/yum.repos.d/*.repo. A section header[id]starts each repository.dnf config-manager --dump REPOIDprints the effective settings.Solution
dnf repolist dnf repoinfo rhel-10-for-x86_64-baseos-rpms 2>/dev/null | head -20 grep -l '^\[' /etc/yum.repos.d/*.repo dnf config-manager --dump | sed -n 1,25p - Practice
A local repository
Make a repository from the packages in
/srv/repo(put a few.rpmfiles there, for example fromdnf download tree nano). Create the metadata, write a repository file withgpgcheck=0only for this test, confirmdnfsees it, and install a package from it only (disable the other repositories for that one command).Check your result
ls /srv/repo/repodata/repomd.xmlexists.dnf repolistshows your repo id with a package count.dnf --disablerepo='*' --enablerepo=labrepo install -y treeinstalls the package fromlabrepo.
Hint
createrepo_c /srv/repowritesrepodata/. A repository file is a[id]section withname,baseurl=file:///srv/repo,enabled=1,gpgcheck=0. Rundnf clean allif the repository does not appear straight away.Solution
sudo dnf install -y createrepo_c sudo mkdir -p /srv/repo && cd /srv/repo sudo dnf download --destdir /srv/repo tree nano sudo createrepo_c /srv/repo sudo tee /etc/yum.repos.d/labrepo.repo <<'EOT' [labrepo] name=Lab repository baseurl=file:///srv/repo enabled=1 gpgcheck=0 EOT sudo dnf clean all dnf repolist sudo dnf --disablerepo='*' --enablerepo=labrepo install -y tree - Challenge
Four failures, four causes
Setup: edit
/etc/yum.repos.d/labrepo.repoor the environment to cause these four failures, one at a time, read each message, repair it and rundnf makecacheor the install again. Write for each: the message, the layer (URL, metadata, signature, dependency), and the fix.1 baseurl=file:///srv/repo-missing 2 remove /srv/repo/repodata/repomd.xml 3 gpgcheck=1 with no gpgkey for an unsigned package 4 install a package whose dependency is in a disabled repositoryCheck your result
- 1:
Cannot prepare internal mirrorlist/Failed to download metadata; fix the URL. - 2:
repomd.xmlnot found; regenerate withcreaterepo_c. - 3:
Public key for ... is not installed/GPG check FAILED; import the key or sign; do not disable the check for production. - 4:
nothing provides ... needed by ...; enable the repository that provides it (dnf repoquery --whatprovides).
Hint
dnf -v makecacheandjournalctl -t dnfgive more detail.dnf provides CAPABILITYanddnf repoquery --whatprovides CAPABILITY --disablerepo=... --enablerepo=...find which repository has a missing dependency.Solution
sudo sed -i 's#^baseurl=.*#baseurl=file:///srv/repo-missing#' /etc/yum.repos.d/labrepo.repo sudo dnf makecache 2>&1 | tail -3 sudo sed -i 's#^baseurl=.*#baseurl=file:///srv/repo#' /etc/yum.repos.d/labrepo.repo sudo mv /srv/repo/repodata/repomd.xml /root/ && sudo dnf makecache 2>&1 | tail -3 sudo createrepo_c --update /srv/repo && sudo dnf makecache sudo sed -i 's/^gpgcheck=0/gpgcheck=1/' /etc/yum.repos.d/labrepo.repo sudo dnf --disablerepo='*' --enablerepo=labrepo install -y nano 2>&1 | tail -4 sudo sed -i 's/^gpgcheck=1/gpgcheck=0/' /etc/yum.repos.d/labrepo.repo # lab only sudo dnf repoquery --whatprovides libfoo.so.1 --enablerepo='*' - 1: