{"record":{"id":"e005ae4befc3f746","repo":"passbolt/passbolt_api","slug":"the-metadata-private-key-cleartext-data-should-be-in-json","errorCode":null,"errorMessage":"The metadata private key cleartext data should be in JSON format.","messagePattern":"The metadata private key cleartext data should be in JSON format\\.","errorType":"http","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltCe/Metadata/src/Service/MetadataKeyShareDefaultService.php","lineNumber":174,"sourceCode":"    /**\n     * @param string $clearText private key object in json format\n     * @return void\n     */\n    public function assertPrivateKey(string $clearText): void\n    {\n        if (empty($clearText)) {\n            $msg = __('The metadata private key should not be empty.');\n            throw new InternalErrorException($msg);\n        }\n\n        try {\n            $decoded = json_decode($clearText, true, 2, JSON_THROW_ON_ERROR);\n        } catch (Exception $exception) {\n            if (Configure::read('debug')) {\n                Log::error($clearText);\n            }\n            $msg = __('The metadata private key cleartext data should be in JSON format.');\n            throw new InternalErrorException($msg, 500, $exception);\n        }\n        if (!is_array($decoded) || empty($decoded)) {\n            $msg = __('The metadata private key cleartext data should not be empty.');\n            throw new InternalErrorException($msg);\n        }\n\n        $form = new MetadataCleartextPrivateKeyForm();\n        if (!$form->validate($decoded)) {\n            if (Configure::read('debug')) {\n                Log::error(json_encode($form->getErrors()));\n            }\n            $msg = __('The metadata private key cleartext data is not valid.');\n            throw new InternalErrorException($msg);\n        }\n    }\n\n    /**\n     * Get the OpenPGP Backend ready to decrypt with server key","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Metadata/src/Service/MetadataKeyShareDefaultService.php#L156-L192","documentation":"assertPrivateKey throws InternalErrorException when json_decode of the decrypted metadata private key cleartext fails (JSON_THROW_ON_ERROR). The decrypted data exists but is not valid JSON of depth <= 2, meaning the stored ciphertext does not decrypt to the expected JSON envelope (object containing object 'objectType', 'armored_key', etc.).","triggerScenarios":"shareMetadataKeyWithUser decrypts the server key copy and calls assertPrivateKey; if the plaintext is not parseable JSON (truncated data, double-encrypted payload, binary garbage, wrong version of the cleartext schema), this error is thrown with the raw cleartext logged in debug mode.","commonSituations":"Data written by an older passbolt version using a different cleartext format; ciphertext truncated during import/export; someone stored an armored key string directly instead of the JSON envelope.","solutions":["Enable debug to log the offending cleartext and inspect why it is not JSON","Check the passbolt version that created this metadata private key; migrate/re-import keys created with an incompatible format","Re-create or re-import the metadata private key so the stored data is the expected JSON envelope (json_encode of the cleartext DTO before encryption)","Verify no double-encryption happened: the payload must decrypt exactly once to JSON"],"exampleFix":"// before: storing the armored key directly\nciphertext = encrypt(armoredKey);\n// after: store the JSON envelope required by MetadataCleartextPrivateKeyForm\nciphertext = encrypt(json_encode(['objectType' => 'PASSBOLT_METADATA_PRIVATE_KEY', 'armored_key' => $armoredKey, ...]));","handlingStrategy":"validation","validationCode":"$decoded = json_decode($cleartext, true, 2);\nif (json_last_error() !== JSON_ERROR_NONE || !is_array($decoded)) {\n    throw new \\DomainException('Cleartext is not the expected JSON envelope.');\n}","typeGuard":"function isValidCleartextJson(?string $cleartext): bool {\n    $d = json_decode((string)$cleartext, true, 2);\n    return is_array($d) && !empty($d);\n}","tryCatchPattern":"try {\n    $service->shareMetadataKeysWithUser($uac, $userIds, $keyId);\n} catch (MetadataKeyShareException $e) {\n    if (str_contains($e->getMessage(), 'should be in JSON format')) {\n        // cleartext corrupted/mis-encoded: re-import the metadata key\n    }\n}","preventionTips":["Always json_encode the cleartext DTO before encrypting during import/migration","Decrypt-once discipline: never store an already-encrypted payload as 'cleartext'","Keep passbolt core and Metadata plugin versions aligned to avoid cleartext format drift","Enable debug logging when importing keys to catch non-JSON cleartext early"],"tags":["openpgp","json","metadata-key","data-integrity"],"backgroundTag":"json-parse-error","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"}