Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Linux Admins By James Joyner IV · · 10 min read

Linux Error: NO_PUBKEY / the following signatures couldn't be verified — Cause, Fix, and Troubleshooting Guide

How to fix the Linux apt 'NO_PUBKEY' and 'the following signatures couldn't be verified' error on Ubuntu using the modern signed-by keyring in /etc/apt/keyrings.

  • #linux
  • #troubleshooting
  • #ubuntu
  • #apt
  • #security

Summary

The following signatures couldn't be verified because the public key is not available: NO_PUBKEY <KEYID> means apt downloaded a repository’s signed Release file but does not have the GPG public key to verify it. On Debian/Ubuntu this is a trust problem, not corruption — apt is correctly refusing to trust an unverifiable repo. The modern, secure fix is to fetch the repository’s key into /etc/apt/keyrings/ and reference it with signed-by= in the source entry, not the deprecated apt-key.

Common Symptoms

  • apt-get update warns: W: GPG error: ... NO_PUBKEY 1234ABCD5678EF90.
  • E: The repository '...' is not signed.
  • the following signatures couldn't be verified because the public key is not available.
  • The affected repo’s packages become uninstallable or untrusted.
  • Common right after adding a third-party repo (Docker, Kubernetes, NodeSource, HashiCorp).

Most Likely Causes of the ‘NO_PUBKEY / the following signatures couldn’t be verified’ Error

The most common production cause is adding a third-party apt repository without importing its signing key first. Other causes:

  • A repo signing key rotated/expired and the new key was never installed.
  • A key was installed under the deprecated apt-key/trusted.gpg path that newer apt no longer reads for a signed-by source.
  • A key file placed in /etc/apt/keyrings in the wrong format (ASCII-armored where binary is expected, or vice versa).
  • The deb source line lacks a signed-by= pointer to the keyring.

Quick Triage

# Which key ID is missing?
sudo apt-get update 2>&1 | grep -Eo 'NO_PUBKEY [0-9A-F]+'

# Which source is unsigned?
grep -R "" /etc/apt/sources.list /etc/apt/sources.list.d/

# Do you already have a keyrings directory?
ls -l /etc/apt/keyrings/ 2>/dev/null

Diagnostic Commands

# Extract the exact missing key IDs from the update output
sudo apt-get update 2>&1 | grep -Eo 'NO_PUBKEY [0-9A-F]{8,}'

# Inspect the offending source and confirm whether it uses signed-by=
grep -R "signed-by" /etc/apt/sources.list.d/

# List keys apt currently trusts (legacy + per-repo keyrings)
apt-key list 2>/dev/null   # deprecated, read-only inspection
ls -l /etc/apt/keyrings/ /usr/share/keyrings/

# Inspect a keyring file's contents/format
gpg --show-keys /etc/apt/keyrings/<vendor>.gpg

Note the full key ID (or better, the vendor’s documented key URL) — you will fetch that specific key next.

Fix / Remediation

  1. Fetch the key into /etc/apt/keyrings and wire it with signed-by (recommended, modern approach):

    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.example.com/repo.gpg \
      | sudo gpg --dearmor -o /etc/apt/keyrings/example.gpg
    sudo chmod a+r /etc/apt/keyrings/example.gpg

    Then reference it in the source (create/edit /etc/apt/sources.list.d/example.list):

    echo "deb [signed-by=/etc/apt/keyrings/example.gpg] https://download.example.com/apt stable main" \
      | sudo tee /etc/apt/sources.list.d/example.list
    sudo apt-get update
  2. If the vendor only publishes a key ID, pull it from a keyserver into a dedicated keyring (not the global trust store):

    sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/example.gpg \
      --keyserver keyserver.ubuntu.com --recv-keys <KEYID>
  3. Point the source at that keyring with signed-by=/etc/apt/keyrings/example.gpg, then apt-get update.

  4. For a rotated key, install the new key file the same way and remove the stale one from /etc/apt/keyrings or /usr/share/keyrings.

Warning: Do not use apt-key add — it is deprecated and adds keys to a global trust store that applies to every repository, which is a security risk. Always scope keys per repository with signed-by= and a dedicated file in /etc/apt/keyrings/.

Validation

# Update should now complete with no GPG/NO_PUBKEY warnings
sudo apt-get update
sudo apt-get update 2>&1 | grep -i 'NO_PUBKEY\|not signed' || echo "OK: repo verified"

# Confirm the source is bound to a keyring
grep -R "signed-by" /etc/apt/sources.list.d/<file>.list

# Packages from the repo now install as trusted
apt-cache policy <pkg-from-that-repo>

Prevention

  • Always import a repo’s signing key into /etc/apt/keyrings and bind it with signed-by= when adding the source.
  • One keyring file per vendor — never share a global trusted keyring across repos.
  • Track key expiry/rotation for third-party repos and update keys before they lapse.
  • Keep system time correct (NTP); a wrong clock makes valid signatures appear expired/not-yet-valid.
  • On RHEL/Rocky/Alma the analog is importing the repo GPG key with rpm --import <url> and setting gpgcheck=1 in the .repo file; the trust model (per-repo keys, verify before install) is the same.

Final Notes

NO_PUBKEY is apt doing its job: refusing to trust a repo it cannot verify. Fix it the modern way — a per-repo key in /etc/apt/keyrings bound with signed-by= — and leave apt-key behind. Keep the clock correct and track key rotations so trusted repos stay trusted.

Want faster Linux incident response? Use DevOps AI Toolkit to turn production errors into clear diagnostics, remediation steps, and reusable runbooks.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.