passbolt/passbolt_api · error · InternalErrorException
The metadata private key cleartext data should not be empty.
Error message
The metadata private key cleartext data should not be empty.
What it means
assertPrivateKey throws InternalErrorException when the decoded JSON cleartext is not a non-empty array (null, scalar, or empty object/array). The data parsed as JSON but does not carry the expected key material structure.
Solutions
- Inspect the stored record and re-import/re-create the metadata private key with the full JSON envelope
- Check the code path that originally created the server copy for a bug that wrote an empty payload
- Validate the cleartext with json_decode before encrypting it during import to catch empties early
Example fix
// before
$ciphertext = $gpg->encrypt(json_encode($data) ?? '');
// after
$json = json_encode($data);
if (!is_array(json_decode($json, true)) || empty(json_decode($json, true))) {
throw new \InvalidArgumentException('Refusing to encrypt empty metadata private key cleartext');
}
$ciphertext = $gpg->encrypt($json, true); Defensive patterns
Strategy: validation
Validate before calling
$decoded = json_decode($cleartext, true, 2);
if (!is_array($decoded) || $decoded === []) {
throw new \DomainException('Decoded cleartext must be a non-empty array.');
} Type guard
function isNonEmptyArrayJson(string $cleartext): bool {
$d = json_decode($cleartext, true, 2);
return is_array($d) && count($d) > 0;
} Try / catch
try {
$service->shareMetadataKeysWithUser($uac, $userIds, $keyId);
} catch (MetadataKeyShareException $e) {
if (str_contains($e->getMessage(), 'cleartext data should not be empty')) {
// stored payload decodes to null/empty: re-import or restore the key
}
} Prevention
- Reject "null"/"[]" JSON payloads at import time, not just at share time
- Ensure interrupted writes cannot truncate the encrypted payload (use transactions)
- Run a data-integrity check over metadata_private_keys after bulk imports
- Test share flows after any custom migration touching metadata private keys
When it happens
Trigger: shareMetadataKeyWithUser path: decrypted cleartext decodes to JSON null (the string "null"), a scalar, or an empty object, so !is_array($decoded) || empty($decoded) triggers this InternalErrorException.
Common situations: Cleartext stored as the JSON literal "null" or "[]"; encoding bug that wrote an empty payload; partial write of the encrypted data during an interrupted operation.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- The metadata private key cleartext data should be in JSON…
- Could not validate metadata key data.
- The metadata could not be encrypted with the metadata key…
- The metadata could not be encrypted with the metadata key id
- The metadata private key cleartext data is not valid.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/c6c1bd11d241c25a.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltCe/Metadata/src/Service/MetadataKeyShareDefaultService.php:178
public function assertPrivateKey(string $clearText): void
{
if (empty($clearText)) {
$msg = __('The metadata private key should not be empty.');
throw new InternalErrorException($msg);
}
try {
$decoded = json_decode($clearText, true, 2, JSON_THROW_ON_ERROR);
} catch (Exception $exception) {
if (Configure::read('debug')) {
Log::error($clearText);
}
$msg = __('The metadata private key cleartext data should be in JSON format.');
throw new InternalErrorException($msg, 500, $exception);
}
if (!is_array($decoded) || empty($decoded)) {
$msg = __('The metadata private key cleartext data should not be empty.');
throw new InternalErrorException($msg);
}
$form = new MetadataCleartextPrivateKeyForm();
if (!$form->validate($decoded)) {
if (Configure::read('debug')) {
Log::error(json_encode($form->getErrors()));
}
$msg = __('The metadata private key cleartext data is not valid.');
throw new InternalErrorException($msg);
}
}
/**
* Get the OpenPGP Backend ready to decrypt with server key
*
* @param \App\Utility\OpenPGP\OpenPGPBackend $gpg for example OpenPGPBackendFactory::get()
* @param string|null $createdBy uuid of user
* @return \App\Utility\OpenPGP\OpenPGPBackend backend configured to use server keysView on GitHub (pinned to 31c1bbc10f)