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

  1. Inspect gpg's import_result output/status to see why the import failed (gpg.import_keys returns detailed results).
  2. Verify the base64 string decodes to a valid key: base64 -d key.b64 | gpg --list-packets.
  3. Regenerate the base64 encoding from the original key file (base64 -w0 private.key) and re-set the CI secret.
  4. 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

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


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/1d8a896b02f256a1. Report an issue: GitHub.