dotnet/runtime · error · Exception
Signature verification failed: {result.stderr.decode('utf-8'
Error message
Signature verification failed: {result.stderr.decode('utf-8')} What it means
With --force-check-gpg, install-debs.py downloads Release and Release.gpg and runs gpgv to verify the detached signature against a keyring. If gpgv exits non-zero (expired/revoked/missing key, malformed signature, wrong keyring, or tampered Release), the build refuses to proceed and surfaces gpgv's stderr so the operator can see the exact OpenPGP failure.
Source
Thrown at eng/common/cross/install-debs.py:135
release_gpg_url = f"{mirror}/dists/{suite}/Release.gpg"
with tempfile.NamedTemporaryFile() as release_file, tempfile.NamedTemporaryFile() as release_gpg_file:
await download_file(session, release_url, release_file.name)
await download_file(session, release_gpg_url, release_gpg_file.name)
print("Verifying signature of Release with Release.gpg.")
# Use gpgv rather than gpg for verification. gpgv verifies a detached
# signature against a fixed keyring without involving gpg-agent or
# keyboxd, which makes it robust on hosts running GnuPG 2.4+ (e.g. Azure
# Linux) where "gpg --keyring" routes through keyboxd and can fail.
verify_command = ["gpgv"]
if keyring:
verify_command += ["--keyring", keyring]
verify_command += [release_gpg_file.name, release_file.name]
result = subprocess.run(verify_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if result.returncode != 0:
raise Exception(f"Signature verification failed: {result.stderr.decode('utf-8')}")
print("Signature verified successfully.")
with open(release_file.name) as f:
return f.read()
def parse_release_file(content, path):
"""Parses the Release file and returns sha256 checksum of the specified path."""
# data looks like this:
# <checksum> <size> <path>
matches = re.findall(r'^ (\S*) +(\S*) +(\S*)$', content, re.MULTILINE)
for entry in matches:
# the file has both md5 and sha256 checksums, we want sha256 which has a length of 64
if entry[2] == path and len(entry[0]) == 64:
return entry[0]
View on GitHub (pinned to 60108ba66e)
Solutions
- Install the appropriate archive keyring package (e.g. debian-archive-keyring, ubuntu-archive-keyring, debian-ports-archive-keyring) and point --keyring at it.
- Update the keyring package to the latest version so it contains the current signing key.
- Read the embedded gpgv stderr in the exception - 'NO_PUBKEY' tells you which key id to import.
- As a last resort in a trusted environment, drop --force-check-gpg, but prefer fixing the keyring.
Example fix
# before python3 install-debs.py --force-check-gpg --keyring /tmp/old.kbx --suite trixie ... # Signature verification failed: NO_PUBKEY ABCD1234... # after apt-get install -y debian-archive-keyring python3 install-debs.py --force-check-gpg --keyring /usr/share/keyrings/debian-archive-keyring.gpg --suite trixie ...
Defensive patterns
Strategy: validation
Validate before calling
# Verify the keyring contains the suite's signing key BEFORE the full build.
import subprocess
def keyring_has_key(keyring: str, key_id: str) -> bool:
rc = subprocess.run(['gpg', '--no-default-keyring', '--keyring', keyring, '--list-keys', key_id],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return rc.returncode == 0
# Or test gpgv directly against Release/Release.gpg of the chosen suite. Try / catch
try:
main()
except Exception as e:
if 'Signature verification failed' in str(e):
print('Install/update the archive keyring, then re-run with --force-check-gpg.')
sys.exit(2)
raise Prevention
- Install the latest debian-archive-keyring / ubuntu-archive-keyring / debian-ports-archive-keyring.
- Pass --keyring explicitly to avoid GnuPG default keybox routing issues (gpgv is used intentionally).
- Read the NO_PUBKEY line in the error to import the exact missing key.
When it happens
Trigger: gpgv returns non-zero at install-debs.py:132-135. Caused by: the suite's signing key rotated and your keyring lacks the new one, the keyring path is wrong/empty, the Release.gpg is stale relative to Release, or GnuPG 2.4+ keyboxd routing issues (the comment notes gpgv was chosen specifically to avoid that).
Common situations: Forgetting to pass --keyring or pointing it at an outdated file. Distribution rolled its archive key (Debian does this periodically). Behind a proxy that corrupted Release.gpg. Host with a partially-initialized GnuPG config.
Related errors
- SHA256 mismatch for {path}: expected {packages_sha}, got {sh
- Could not find checksum for {path} in Release file.
- SHA256 mismatch for {url}: expected {checksum}, got {sha256}
- Failed to download {url}, Status Code: {response.status}
- Failed to download {url} after {max_retries} attempts.
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/81ae112157195e05.
Report an issue: GitHub.