{"record":{"id":"5f4466ed1f7e81fe","repo":"passbolt/passbolt_api","slug":"could-not-validate-user-data-5f4466","errorCode":null,"errorMessage":"Could not validate user data.","messagePattern":"Could not validate user data\\.","errorType":"http","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"src/Service/OpenPGP/OpenPGPCommonUserOperationsTrait.php","lineNumber":43,"sourceCode":"\ntrait OpenPGPCommonUserOperationsTrait\n{\n    /**\n     * Get the OpenPGP Backend ready to encryption with user key\n     *\n     * @param \\App\\Utility\\OpenPGP\\OpenPGPBackend $gpg for example OpenPGPBackendFactory::get()\n     * @param \\App\\Model\\Entity\\Gpgkey $userKey entity\n     * @return \\App\\Utility\\OpenPGP\\OpenPGPBackend backend configured to use user key to encrypt\n     * @throws \\Cake\\Http\\Exception\\InternalErrorException if the user key cannot be loaded\n     */\n    protected function setEncryptKeyWithUserKey(OpenPGPBackend $gpg, Gpgkey $userKey): OpenPGPBackend\n    {\n        // Set encryption key as the one from the user\n        try {\n            $this->assertUserKey($userKey);\n        } catch (Exception $exception) {\n            $msg = __('Could not validate user data.');\n            throw new InternalErrorException($msg, 500, $exception);\n        }\n        try {\n            $gpg->setEncryptKeyFromFingerprint($userKey->fingerprint);\n        } catch (Exception $exception) {\n            // Try to import the key in keyring again\n            try {\n                $gpg->importKeyIntoKeyring($userKey->armored_key);\n                $gpg->setEncryptKeyFromFingerprint($userKey->fingerprint);\n            } catch (Exception $exception) {\n                if (Configure::read('debug')) {\n                    Log::error(json_encode($userKey));\n                }\n                $msg = __('Could not import the user OpenPGP key.');\n                throw new InternalErrorException($msg, 500, $exception);\n            }\n        }\n\n        return $gpg;","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Service/OpenPGP/OpenPGPCommonUserOperationsTrait.php#L25-L61","documentation":"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.","triggerScenarios":"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().","commonSituations":"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.","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."],"exampleFix":"// before\n$gpg = $this->setEncryptKeyWithUserKey($gpg, $user->gpgkey); // may be null/partial\n// after\nif ($user->gpgkey === null\n    || !isset($user->gpgkey->armored_key, $user->gpgkey->fingerprint)\n    || !PublicKeyValidationService::isValidFingerprint($user->gpgkey->fingerprint)) {\n    throw new BadRequestException(__('The user key data is incomplete.'));\n}\n$gpg = $this->setEncryptKeyWithUserKey($gpg, $user->gpgkey);","handlingStrategy":"validation","validationCode":"use App\\Service\\OpenPGP\\PublicKeyValidationService;\n\nfunction canUseUserKeyForEncryption(\\App\\Model\\Entity\\Gpgkey $userKey): bool\n{\n    return isset($userKey->armored_key, $userKey->fingerprint)\n        && is_string($userKey->fingerprint)\n        && PublicKeyValidationService::isValidFingerprint($userKey->fingerprint)\n        && is_string($userKey->armored_key)\n        && PublicKeyValidationService::parseAndValidatePublicKey($userKey->armored_key);\n}","typeGuard":"function isUsableGpgkey(mixed $key): bool\n{\n    return $key instanceof \\App\\Model\\Entity\\Gpgkey\n        && isset($key->armored_key, $key->fingerprint)\n        && is_string($key->armored_key)\n        && is_string($key->fingerprint);\n}","tryCatchPattern":"try {\n    $gpg = $this->setEncryptKeyWithUserKey($gpg, $userKey);\n} catch (InternalErrorException $e) {\n    // inspect $e->getPrevious() for the exact assertUserKey failure\n    error_log('User key validation failed: ' . ($e->getPrevious()?->getMessage() ?? $e->getMessage()));\n    throw new BadRequestException('The user OpenPGP key data is incomplete or invalid.');\n}","preventionTips":["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."],"tags":["openpgp","gpg","user-key","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}