53 developer tools, always updated, new upstream releases land in apt within hours. Join the Discord

📅 From , the apt mirror will require a subscription. See pricing · 🆓 There is an always-free mirror

🔑 apt GPG key errors, and how to fix them

NO_PUBKEY, “is not signed”, and the legacy trusted.gpg warning

⚡ The short answer. Almost every apt key error comes from one of four things: the key was never imported, it was saved in the wrong format, it was saved in the wrong place, or the keyring file is not readable by the _apt user. The modern fix for all of them is the same, an armoured key dearmoured into /etc/apt/keyrings/, mode 644, referenced by signed-by= in that one repository's sources entry. Never apt-key add, and never a key in /etc/apt/trusted.gpg.

🩺 Find your error

NO_PUBKEY

W: GPG error: https://deb.griffo.io/apt trixie InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 7808B4DD62C41256
E: The repository 'https://deb.griffo.io/apt trixie InRelease' is not signed.

apt fetched the index, found a valid signature, and has no matching public key. The key is missing, is in a file apt was not told to look at, or is not in the binary format apt expects. Go to the fix.

“is not signed” on its own

E: The repository 'https://… trixie InRelease' is not signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.

Same cause as above in most cases. It genuinely means "unsigned" only when the repository ships no InRelease or Release.gpg at all, check by opening <repo>/dists/<suite>/InRelease in a browser. For this repository it is always present, so the key is the problem, not the archive.

Legacy trusted.gpg keyring

W: https://…/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg),
   see the DEPRECATION section in apt-key(8) for details.

Not fatal yet, and worth fixing anyway: a key in trusted.gpg is trusted for every repository on the machine, not just the one it belongs to. That is the whole reason apt-key was deprecated. Move it, as below.

“Release file is not valid yet”

E: Release file for https://… is not valid yet (invalid for another 5h 12min 4s).

Not a key problem, your system clock is wrong. Fix the clock (sudo timedatectl set-ntp true) rather than reaching for -o Acquire::Check-Valid-Until=false.

✅ The fix that covers all of them

Using this repository as the worked example; substitute your own key URL and host for any other repository.

Run the commands
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://deb.griffo.io/EA0F721D231FDD3A0A17B9AC7808B4DD62C41256.asc | sudo gpg --dearmor --yes -o /etc/apt/keyrings/deb.griffo.io.gpg
sudo chmod 644 /etc/apt/keyrings/deb.griffo.io.gpg
echo "deb [signed-by=/etc/apt/keyrings/deb.griffo.io.gpg] https://deb.griffo.io/apt $(lsb_release -sc 2>/dev/null) main" | sudo tee /etc/apt/sources.list.d/deb.griffo.io.list > /dev/null
sudo apt update
install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://deb.griffo.io/EA0F721D231FDD3A0A17B9AC7808B4DD62C41256.asc | gpg --dearmor --yes -o /etc/apt/keyrings/deb.griffo.io.gpg
chmod 644 /etc/apt/keyrings/deb.griffo.io.gpg
echo "deb [signed-by=/etc/apt/keyrings/deb.griffo.io.gpg] https://deb.griffo.io/apt $(lsb_release -sc 2>/dev/null) main" | tee /etc/apt/sources.list.d/deb.griffo.io.list > /dev/null
apt update
sudo apt install extrepo
sudo extrepo enable griffo
sudo apt update

🧩 About the extrepo option. extrepo is Debian's own tool for external repositories: it writes the sources file and installs the signing key for you, checking the key against signed metadata first. This repository is registered with it as griffo, and the always-free mirror as griffo-free, so on Debian (bookworm, trixie, forky and sid) the commands above are the whole setup.

extrepo sets up the sources file and the key only, so a subscription's credentials still go in /etc/apt/auth.conf.d/deb.griffo.io.conf. Ubuntu is not covered, because extrepo publishes metadata for Debian suites only: there, use the sudo or root commands.

Four details in there do all the work, and each one is a common failure on its own:

🧹 Migrating a key off the legacy keyring

List what is in the old keyring, export the one you want, then remove it:

sudo apt-key list 2>/dev/null | grep -B2 -A2 griffo
sudo gpg --keyring /etc/apt/trusted.gpg --export 7808B4DD62C41256 | sudo tee /etc/apt/keyrings/deb.griffo.io.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/deb.griffo.io.gpg
sudo apt-key --keyring /etc/apt/trusted.gpg del 7808B4DD62C41256
apt-key list 2>/dev/null | grep -B2 -A2 griffo
gpg --keyring /etc/apt/trusted.gpg --export 7808B4DD62C41256 | tee /etc/apt/keyrings/deb.griffo.io.gpg > /dev/null
chmod 644 /etc/apt/keyrings/deb.griffo.io.gpg
apt-key --keyring /etc/apt/trusted.gpg del 7808B4DD62C41256

Then add signed-by= to that repository's sources entry, as above. Keys in /etc/apt/trusted.gpg.d/*.gpg are still honoured and are not deprecated in the same way, but they are also system-wide, moving them to keyrings/ plus signed-by= is still the better end state.

🔍 Verify it worked

# the key apt will actually use, and its fingerprint
gpg --show-keys /etc/apt/keyrings/deb.griffo.io.gpg

# what apt itself thinks of the repository
apt-cache policy
sudo apt update
# the key apt will actually use, and its fingerprint
gpg --show-keys /etc/apt/keyrings/deb.griffo.io.gpg

# what apt itself thinks of the repository
apt-cache policy
apt update

The fingerprint must read EA0F 721D 231F DD3A 0A17  B9AC 7808 B4DD 62C4 1256. If it does not, you have imported someone else's key, stop and re-fetch it from the source. How these packages are built and signed →

🚫 What not to do

🔗 Related