passbolt/passbolt_api · error · InternalErrorException

The metadata could not be encrypted with the metadata key…

Error message

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

What it means

Shared-folder migration encrypts metadata with the active metadata (shared) key; any exception from backend setup, metadata key loading, JSON encoding, or gpg->encrypt() is re-thrown as InternalErrorException prefixed with the original message and suffixed with the metadata key ID, chaining the original exception.

Solutions

  1. Inspect the prefixed exceptionMessage / chained exception to find the root GPG error.
  2. Verify the metadata key is active, not expired/revoked, and its armored public key imports cleanly into the keyring.
  3. Check GNUPGHOME configuration and permissions for the PHP process, and that setEncryptKeyWithMetadataKey succeeded.
  4. Validate the metadata payload is UTF-8 clean before json_encode, or sanitize folder names first.

Example fix

// before
$metadataClearText = json_encode($metadataArray, JSON_THROW_ON_ERROR);
$metadataEncrypted = $gpg->encrypt($metadataClearText, true);
// after: guard encoding and key import
$metadataClearText = json_encode(
    $this->sanitizeUtf8($metadataArray),
    JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE
);
if (!$metadataKey->expired && !$metadataKey->deleted) {
    $metadataEncrypted = $gpg->encrypt($metadataClearText, true);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: metadata key active and importable
$gpg = OpenPGPBackendFactory::get();
$gpg->clearKeys();
$gpg->importKeyIntoKeyring($metadataKey->armored_key);
$gpg->encrypt('test', true); // smoke-test encryption with the metadata key

Try / catch

try {
    $service->migrate($uac);
} catch (\Cake\Http\Exception\InternalErrorException $e) {
    error_log($e->getPrevious()?->getMessage() ?? $e->getMessage());
    // re-import/rotate the metadata key identified in the message, then retry
}

Prevention

When it happens

Trigger: Calling migrate → migrateShared when encryption with the metadata key fails: key material/fingerprint invalid or missing from keyring, key expired/revoked, gpg binary issues, or JSON_THROW_ON_ERROR firing while encoding the metadata array.

Common situations: Metadata key deleted from keyring but row still active; mismatched armored key data in DB; wrong GNUPGHOME; folder names with invalid UTF-8 breaking json_encode.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at plugins/PassboltCe/Metadata/src/Service/Migration/MigrateAllV4FoldersToV5Service.php:203

     * @return void
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When there is no metadata key record.
     */
    private function migrateShared(MetadataFolderDto $dto, Folder $folder): void
    {
        $metadataArray = $dto->getClearTextMetadata();
        $metadataKey = $this->getMetadataKeyForEncryption();

        try {
            $gpg = OpenPGPBackendFactory::get();
            $gpg->clearKeys();
            $gpg = $this->setSignKeyWithServerKey($gpg);
            $gpg = $this->setEncryptKeyWithMetadataKey($gpg, $metadataKey);
            $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 metadata key id: {0}.', $metadataKey->id);
            throw new InternalErrorException($msg, 500, $exception);
        }

        $this->updateFolder($folder, [
            'name' => null,
            'metadata' => $metadataEncrypted,
            'metadata_key_id' => $metadataKey->id,
            'metadata_key_type' => 'shared_key',
            //TODO support nullable resource.modified_by to allow server side modification
            //'modified_by' => null,
        ]);
    }

    /**
     * Updates entity with given data.
     *
     * @param \Passbolt\Folders\Model\Entity\Folder $folder Folder entity to update.
     * @param array $data Data to update.
     * @return void

View on GitHub (pinned to 31c1bbc10f)