passbolt/passbolt_api · error · InternalErrorException

Could not import the user OpenPGP key.

Error message

Could not import the user OpenPGP key.

What it means

setEncryptKeyWithUserKey() first tries setEncryptKeyFromFingerprint($userKey->fingerprint); if the key is not in the GnuPG keyring it retries by importing armored_key via importKeyIntoKeyring() and setting the key again. If that fallback also throws, the InternalErrorException 'Could not import the user OpenPGP key.' (HTTP 500) is raised. The key data itself passed validation, but the GPG keyring refuses to store or use it.

Solutions

  1. Check the chained exception message in the log/debug output — it contains the underlying gnupg error explaining why the import or key selection failed.
  2. Verify the web-server user's GnuPG keyring permissions and GNUPGHOME directory (ownership, 700, readable keyring files) and re-run the operation.
  3. Manually test importing the armored key with gpg --import to see gnupg's own error for that key.
  4. Have the user re-generate or re-upload their key if the stored key is rejected by the installed gnupg version (e.g. keys using deprecated algorithms).
  5. If keyring corruption is suspected, rebuild the keyring (delete/recreate the gnupg homedir for the web user) and let passbolt re-import keys on demand.

Example fix

// before: relying on keyring having the key
$gpg->setEncryptKeyFromFingerprint($userKey->fingerprint);
// after: pre-check key presence and surface the gnupg error clearly
try {
    $gpg->setEncryptKeyFromFingerprint($userKey->fingerprint);
} catch (Exception $e) {
    $imported = $gpg->importKeyIntoKeyring($userKey->armored_key);
    if (!$imported) {
        throw new InternalErrorException(
            __('The user key could not be imported into the keyring: {0}', $e->getMessage())
        );
    }
    $gpg->setEncryptKeyFromFingerprint($userKey->fingerprint);
}
Defensive patterns

Strategy: try-catch

Validate before calling

use App\Service\OpenPGP\PublicKeyValidationService;

if (!PublicKeyValidationService::parseAndValidatePublicKey($userKey->armored_key)) {
    throw new BadRequestException('User armored key is not a valid public key.');
}
if (!is_dir(getenv('GNUPGHOME') ?: sys_get_temp_dir())) {
    throw new RuntimeException('GnuPG homedir is not available.');
}

Type guard

function isNonEmptyString(mixed $value): bool
{
    return is_string($value) && $value !== '';
}

// use: isNonEmptyString($userKey->armored_key) && isNonEmptyString($userKey->fingerprint)

Try / catch

try {
    $gpg = $this->setEncryptKeyWithUserKey($gpg, $userKey);
} catch (InternalErrorException $e) {
    $reason = $e->getPrevious()?->getMessage() ?? 'unknown gnupg error';
    // e.g. keyring permission problem vs bad key data
    $this->log(__('Keyring import failed for {0}: {1}', $userKey->fingerprint, $reason));
    throw new InternalErrorException(
        __('The user key could not be imported. Check the server GPG keyring: {0}', $reason)
    );
}

Prevention

When it happens

Trigger: Calling setEncryptKeyWithUserKey() when the user's public key is absent from the server keyring AND the re-import of $userKey->armored_key fails (malformed armor despite passing validation, expired/revoked key rejected by gnupg, keyring permission or gnupg homedir issues, key already present with different fingerprint data).

Common situations: GnuPG homedir (e.g. /home/www-data/.gnupg) owned by wrong user or wrong permissions after server migration; different gnupg version on new server rejecting old key packets; keyring wiped/rebuilt (keyring dir deleted); armored key stored with broken line endings after a database import/export; corrupted key from third-party import scripts.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/e590a8a5d8e43d78. Report an issue: GitHub.

Appendix: source

Thrown at src/Service/OpenPGP/OpenPGPCommonUserOperationsTrait.php:57

        try {
            $this->assertUserKey($userKey);
        } catch (Exception $exception) {
            $msg = __('Could not validate user data.');
            throw new InternalErrorException($msg, 500, $exception);
        }
        try {
            $gpg->setEncryptKeyFromFingerprint($userKey->fingerprint);
        } catch (Exception $exception) {
            // Try to import the key in keyring again
            try {
                $gpg->importKeyIntoKeyring($userKey->armored_key);
                $gpg->setEncryptKeyFromFingerprint($userKey->fingerprint);
            } catch (Exception $exception) {
                if (Configure::read('debug')) {
                    Log::error(json_encode($userKey));
                }
                $msg = __('Could not import the user OpenPGP key.');
                throw new InternalErrorException($msg, 500, $exception);
            }
        }

        return $gpg;
    }

    /**
     * Get the OpenPGP Backend ready to verify with user key
     *
     * @param \App\Utility\OpenPGP\OpenPGPBackend $gpg for example OpenPGPBackendFactory::get()
     * @param \App\Model\Entity\Gpgkey $userKey entity
     * @return \App\Utility\OpenPGP\OpenPGPBackend backend configured to use user key to verify
     * @throws \Cake\Http\Exception\InternalErrorException if the user key cannot be loaded
     */
    protected function setVerifyKeyWithUserKey(OpenPGPBackend $gpg, Gpgkey $userKey): OpenPGPBackend
    {
        // Set encryption key as the one from the user
        try {

View on GitHub (pinned to 31c1bbc10f)