passbolt/passbolt_api · error · InternalErrorException

The metadata could not be encrypted with the user id: .

Error message

{exceptionMessage} The metadata could not be encrypted with the user id: {0}.

What it means

During migration of v4 resources to v5 metadata, the personal-resource path encrypts the resource's metadata with the owner's OpenPGP key. If $gpg->encrypt() throws (missing/invalid user key, keyring failure, bad clear text), the exception is wrapped in a CakePHP InternalErrorException with this appended message identifying the user whose key failed.

Solutions

  1. Verify the user has an enabled GPG key (users.gpgkey) and that the public key exists in the server keyring (gpg --list-keys <fingerprint>), import it if missing
  2. Re-run the migration with debug enabled to see the underlying wrapped exception message (it is prefixed before this text)
  3. Check PHP GnuPG/pear-crypt-gpg configuration and keyring home directory permissions for the web server user
  4. Fix or reset the affected user's key data, then re-run the migration for the failing resource

Example fix

// before: user without key discovered mid-migration
$metadataEncrypted = $gpg->encrypt($metadataClearText, true); // throws
// after: pre-check before migrating
if (!$user->gpgkey || $user->gpgkey->deleted) {
    throw new RecordNotFoundException(__('User {0} has no usable GPG key.', $user->id));
}
$metadataEncrypted = $gpg->encrypt($metadataClearText, true);
Defensive patterns

Strategy: try-catch

Validate before calling

// before migration, per user
if (!$user->gpgkey || $user->gpgkey->deleted) {
    throw new \LogicException("User {$user->id} has no GPG key");
}
$fp = $user->gpgkey->fingerprint;
$inKeyring = in_array($fp, OpenPGPBackend::getFingerprintsInKeyring(), true);
if (!$inKeyring) {
    throw new \LogicException("Key {$fp} not in server keyring");
}

Type guard

function hasUsableGpgKey(\App\Model\Entity\User $user): bool {
    return $user->gpgkey !== null
        && $user->gpgkey->deleted === false
        && is_string($user->gpgkey->fingerprint)
        && strlen($user->gpgkey->fingerprint) === 40;
}

Try / catch

try {
    $metadataEncrypted = $gpg->encrypt($metadataClearText, true);
} catch (\Exception $e) {
    // inspect $e->getMessage(); if keyring missing, import user key then retry once
}

Prevention

When it happens

Trigger: migrate() -> migratePersonal() calls setEncryptKeyWithUserKey($gpg, $user->gpgkey) and then encrypt(); the user has no GPG key, the key is not in the server keyring, the key is expired/revoked, or json_encode of $metadataArray throws.

Common situations: Migration command (migrateMetadata resources) run on a server where some users' public keys were never imported; user deleted their account key or key was rotated without re-import; GnuPG extension keyring permission issues on the host.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

Thrown at plugins/PassboltCe/Metadata/src/Service/Migration/MigrateAllV4ResourcesToV5Service.php:179

            $msg .= __('The metadata could not be encrypted for permission id: {0}.', $permission->id);
            throw new InternalErrorException($msg);
        }
        if (!isset($user->gpgkey)) {
            $msg = __('No OpenPGP key found for the user.') . ' ';
            $msg .= __('The metadata could not be encrypted with the user id: {0}.', $user->id);
            throw new InternalErrorException($msg);
        }
        try {
            $gpg = OpenPGPBackendFactory::get();
            $gpg->clearKeys();
            $gpg = $this->setSignKeyWithServerKey($gpg);
            $gpg = $this->setEncryptKeyWithUserKey($gpg, $user->gpgkey);
            $metadataClearText = json_encode($metadataArray, JSON_THROW_ON_ERROR);
            $metadataEncrypted = $gpg->encrypt($metadataClearText, true);
        } catch (Exception $exception) {
            $msg = $exception->getMessage() . ' ';
            $msg .= __('The metadata could not be encrypted with the user id: {0}.', $user->id);
            throw new InternalErrorException($msg, 500, $exception);
        }

        $this->updateResource($resource, [
            'name' => null,
            'username' => null,
            'uri' => null,
            'description' => null,
            'resource_type_id' => $this->getV5ResourceType($resource->resource_type_id),
            'metadata' => $metadataEncrypted,
            'metadata_key_id' => $user->gpgkey->id,
            'metadata_key_type' => 'user_key',
        ]);
    }

    /**
     * @param \Passbolt\Metadata\Model\Dto\MetadataResourceDto $dto DTO.
     * @param \App\Model\Entity\Resource $resource Resource entity.
     * @return void

View on GitHub (pinned to 31c1bbc10f)