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
- 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
- Re-run the migration with debug enabled to see the underlying wrapped exception message (it is prefixed before this text)
- Check PHP GnuPG/pear-crypt-gpg configuration and keyring home directory permissions for the web server user
- 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
- Ensure the import command syncs all users' public keys into the server keyring before migrating
- Health-check user GPG keys (deleted/expired) before running bulk migrations
- Keep PHP gnupg/crypt-gpg extensions and keyring directory permissions verified on the host
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
- No OpenPGP key found for the user. The metadata could not…
- The metadata could not be encrypted with the user id: .
- The metadata could not be encrypted with the metadata key…
- No OpenPGP key found for the user. The metadata could not…
- No user provided. The metadata could not be encrypted for…
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 voidView on GitHub (pinned to 31c1bbc10f)