passbolt/passbolt_api · error · InternalErrorException

The metadata private key cleartext data is not valid.

Error message

The metadata private key cleartext data is not valid.

What it means

assertPrivateKey throws InternalErrorException when the decoded cleartext array fails validation by MetadataCleartextPrivateKeyForm. The data is valid non-empty JSON but missing required fields (e.g. objectType, armored_key) or violating the form's schema for a metadata private key cleartext.

Solutions

  1. Enable debug to see json_encode($form->getErrors()) and identify which fields fail
  2. Compare the cleartext against the MetadataCleartextPrivateKeyForm schema and fix missing/invalid fields (objectType, armored_key, etc.)
  3. Re-import or regenerate the metadata private key using the official passbolt migration tooling/commands rather than custom scripts
  4. Ensure all plugins are upgraded together so the cleartext schema version matches what the server expects

Example fix

// before: incomplete cleartext
{"armored_key": "-----BEGIN PGP PRIVATE KEY BLOCK-----..."}
// after: schema-conformant cleartext
{"objectType": "PASSBOLT_METADATA_PRIVATE_KEY", "armored_key": "-----BEGIN PGP PRIVATE KEY BLOCK-----...", "created": "2024-01-01T00:00:00+00:00", "modified": "2024-01-01T00:00:00+00:00"}
Defensive patterns

Strategy: validation

Validate before calling

$decoded = json_decode($cleartext, true, 2);
$form = new \Passbolt\Metadata\Form\MetadataCleartextPrivateKeyForm();
if (!is_array($decoded) || !$form->validate($decoded)) {
    throw new \DomainException('Cleartext schema invalid: ' . json_encode($form->getErrors()));
}

Type guard

function passesCleartextForm(array $decoded): bool {
    return isset($decoded['objectType'], $decoded['armored_key'])
        && $decoded['objectType'] === 'PASSBOLT_METADATA_PRIVATE_KEY'
        && is_string($decoded['armored_key']);
}

Try / catch

try {
    $service->shareMetadataKeysWithUser($uac, $userIds, $keyId);
} catch (MetadataKeyShareException $e) {
    if (str_contains($e->getMessage(), 'cleartext data is not valid')) {
        // inspect MetadataCleartextPrivateKeyForm errors in debug logs and re-import conformant data
    }
}

Prevention

When it happens

Trigger: shareMetadataKeyWithUser decrypts the server copy and validates the cleartext structure; a payload missing keys like 'objectType' => 'PASSBOLT_METADATA_PRIVATE_KEY' or a valid 'armored_key', or with extra/invalid fields, fails $form->validate($decoded) and raises this error (form errors logged in debug).

Common situations: Keys imported by tooling that produced a slightly different JSON shape; passbolt version mismatch where the cleartext schema changed; hand-crafted migration/import scripts that omitted required properties.

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


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

Appendix: source

Thrown at plugins/PassboltCe/Metadata/src/Service/MetadataKeyShareDefaultService.php:187

        } 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 keys
     * @throws \Cake\Http\Exception\InternalErrorException if the server key cannot be loaded
     */
    private function setKeyForVerify(OpenPGPBackend $gpg, ?string $createdBy = null): OpenPGPBackend
    {
        // Use server key if no user is defined in createdBy
        if ($createdBy === null) {
            return $this->setVerifyKeyWithServerKey($gpg);
        }

View on GitHub (pinned to 31c1bbc10f)