passbolt/passbolt_api · error · InternalErrorException
Could not validate user data.
Error message
Could not validate user data.
What it means
Before using a user OpenPGP key to encrypt, setEncryptKeyWithUserKey() calls assertUserKey(), which requires the Gpgkey entity to have a non-empty armored_key, a valid fingerprint string, and an armored key that parses as a valid public key. If any of those assertions fail, the underlying InternalErrorException is re-thrown as 'Could not validate user data.' with HTTP 500. It indicates corrupted or incomplete user key data, not a keyring problem.
Solutions
- Inspect the Gpgkey entity for the affected user (gpgkeys table) and verify both fingerprint and armored_key are populated and consistent with each other.
- Re-import or re-save the user's public key so validation rules run, or have the user re-upload their key if the stored key is corrupted.
- Ensure callers pass a fully hydrated App\Model\Entity\Gpgkey (not an array or partial object) into setEncryptKeyWithUserKey.
- Check the chained exception (previous) in logs — the original assertUserKey message tells which field failed ('not available or incomplete').
- Run bin/cake passbolt healthcheck (key checks) to find users with invalid key records.
Example fix
// before
$gpg = $this->setEncryptKeyWithUserKey($gpg, $user->gpgkey); // may be null/partial
// after
if ($user->gpgkey === null
|| !isset($user->gpgkey->armored_key, $user->gpgkey->fingerprint)
|| !PublicKeyValidationService::isValidFingerprint($user->gpgkey->fingerprint)) {
throw new BadRequestException(__('The user key data is incomplete.'));
}
$gpg = $this->setEncryptKeyWithUserKey($gpg, $user->gpgkey); Defensive patterns
Strategy: validation
Validate before calling
use App\Service\OpenPGP\PublicKeyValidationService;
function canUseUserKeyForEncryption(\App\Model\Entity\Gpgkey $userKey): bool
{
return isset($userKey->armored_key, $userKey->fingerprint)
&& is_string($userKey->fingerprint)
&& PublicKeyValidationService::isValidFingerprint($userKey->fingerprint)
&& is_string($userKey->armored_key)
&& PublicKeyValidationService::parseAndValidatePublicKey($userKey->armored_key);
} Type guard
function isUsableGpgkey(mixed $key): bool
{
return $key instanceof \App\Model\Entity\Gpgkey
&& isset($key->armored_key, $key->fingerprint)
&& is_string($key->armored_key)
&& is_string($key->fingerprint);
} Try / catch
try {
$gpg = $this->setEncryptKeyWithUserKey($gpg, $userKey);
} catch (InternalErrorException $e) {
// inspect $e->getPrevious() for the exact assertUserKey failure
error_log('User key validation failed: ' . ($e->getPrevious()?->getMessage() ?? $e->getMessage()));
throw new BadRequestException('The user OpenPGP key data is incomplete or invalid.');
} Prevention
- Always rely on passbolt's own Gpgkey validation rules when saving keys, never insert raw rows into gpgkeys.
- Load the full Gpgkey entity (contain the association) before passing it; avoid partial/select-field queries that drop armored_key or fingerprint.
- Mirror assertUserKey's checks in your service before calling the trait to produce a client-friendly error instead of a 500.
- Add automated tests/fixtures using real, valid armored keys.
- Monitor for NULL armored_key/fingerprint rows in gpgkeys after migrations.
When it happens
Trigger: Calling setEncryptKeyWithUserKey($gpg, $userKey) where $userKey is a Gpgkey entity whose armored_key or fingerprint is null/unset, whose fingerprint fails PublicKeyValidationService::isValidFingerprint(), or whose armored_key fails PublicKeyValidationService::parseAndValidatePublicKey().
Common situations: Data seeded by scripts or fixtures with truncated armored keys; user keys deleted/blanked in the gpgkeys table after partial migrations; passing an entity loaded from an event payload where fields were not hydrated; hand-modified database rows; upgrades between passbolt versions changing key validation rules.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- A valid OpenPGP key must be provided.
- Could not import the user OpenPGP key.
- Could not validate message data.
- Invalid request, message validation rules are missing.
- The armored message could not be validated.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/5f4466ed1f7e81fe.
Report an issue: GitHub.
Appendix: source
Thrown at src/Service/OpenPGP/OpenPGPCommonUserOperationsTrait.php:43
trait OpenPGPCommonUserOperationsTrait
{
/**
* Get the OpenPGP Backend ready to encryption 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 encrypt
* @throws \Cake\Http\Exception\InternalErrorException if the user key cannot be loaded
*/
protected function setEncryptKeyWithUserKey(OpenPGPBackend $gpg, Gpgkey $userKey): OpenPGPBackend
{
// Set encryption key as the one from the user
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;View on GitHub (pinned to 31c1bbc10f)