cloudflare/cloudflared · error · Exception
Failed to import private key
Error message
Failed to import private key
What it means
import_gpg_keys base64-decodes the provided private key material and imports it via python-gnupg; if the import result contains no fingerprints, the key was not accepted by gpg and this exception is raised. This almost always means the key data was invalid, corrupted, or not actually a private key.
Source
Thrown at release_pkgs.py:194
if file.endswith(f"{arch}.rpm"):
new_dir = f"./rpm/{arch}"
os.makedirs(new_dir, exist_ok=True)
old_path = os.path.join(root, file)
new_path = os.path.join(new_dir, file)
shutil.copyfile(old_path, new_path)
self._sign_rpms(new_path, gpg_key_name)
"""
imports gpg keys into the system so reprepro and createrepo can use it to sign packages.
it returns the GPG ID after a successful import
"""
def import_gpg_keys(self, private_key, public_key):
gpg = gnupg.GPG()
private_key = base64.b64decode(private_key)
import_result = gpg.import_keys(private_key)
if not import_result.fingerprints:
raise Exception("Failed to import private key")
public_key = base64.b64decode(public_key)
gpg.import_keys(public_key)
imported_fingerprint = import_result.fingerprints[0]
data = gpg.list_keys(secret=True)
# Find the specific key we just imported by comparing fingerprints
for key in data:
if key["fingerprint"] == imported_fingerprint:
return (key["fingerprint"], key["uids"][0])
raise Exception(f"Could not find imported key with fingerprint {imported_fingerprint}")
def import_multiple_gpg_keys(self, primary_private_key, primary_public_key, secondary_private_key=None, secondary_public_key=None):
"""
Import one or two GPG keypairs. Returns a list of (fingerprint, uid) with the primary first.
"""View on GitHub (pinned to 2253eeeb25)
Solutions
- Inspect gpg's import_result output/status to see why the import failed (gpg.import_keys returns detailed results).
- Verify the base64 string decodes to a valid key: base64 -d key.b64 | gpg --list-packets.
- Regenerate the base64 encoding from the original key file (base64 -w0 private.key) and re-set the CI secret.
- Confirm you are passing the private key (not the public key) to the private_key argument.
Example fix
// before
import_result = gpg.import_keys(private_key)
if not import_result.fingerprints:
raise Exception("Failed to import private key")
// after
import_result = gpg.import_keys(private_key)
if not import_result.fingerprints:
raise Exception("Failed to import private key: {}".format(import_result.results)) Defensive patterns
Strategy: validation
Validate before calling
import base64
data = base64.b64decode(private_key, validate=True)
if b"PRIVATE KEY" not in data and not data.startswith(b"-----BEGIN PGP"):
raise ValueError("private_key does not look like valid PGP key material") Try / catch
try:
keys = importer.import_gpg_keys(priv, pub)
except Exception as e:
logging.error("GPG import failed: %s", e)
raise SystemExit(1) Prevention
- Regenerate CI secrets with base64 -w0 to avoid wrapped/truncated blobs
- Confirm the private key (not the public key) is supplied as private_key
- Test the import locally with gpg --import before wiring into CI
When it happens
Trigger: Importing a private key whose base64 payload does not decode to valid PGP key material, a public key passed where a private key is expected, an empty string, whitespace/newline corruption from a CI secret, or a GPG keychain/agent failure.
Common situations: CI secrets where the base64 blob was truncated or re-wrapped; storing the key double-encoded; passing the public key file into gpg_private_key; GPG_HOME issues causing silent import failures.
Related errors
- Could not find imported key with fingerprint {imported_finge
- No GPG keys were provided for signing
- failed to get checksums: {0}
- the argument path must be a directory
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/1d8a896b02f256a1.
Report an issue: GitHub.