{"record":{"id":"9fceb4df313791f9","repo":"passbolt/passbolt_api","slug":"could-not-validate-metadata-key-data","errorCode":null,"errorMessage":"Could not validate metadata key data.","messagePattern":"Could not validate metadata key data\\.","errorType":"http","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltCe/Metadata/src/Service/OpenPGP/OpenPGPCommonMetadataOperationsTrait.php","lineNumber":47,"sourceCode":"    /**\n     * Get the OpenPGP Backend ready to encryption with shared metadata key\n     *\n     * @param \\App\\Utility\\OpenPGP\\OpenPGPBackend $gpg for example OpenPGPBackendFactory::get()\n     * @param \\Passbolt\\Metadata\\Model\\Entity\\MetadataKey $metadataKey Metadata entity object.\n     * @return \\App\\Utility\\OpenPGP\\OpenPGPBackend backend configured to use server keys\n     * @throws \\Cake\\Http\\Exception\\InternalErrorException if the server key cannot be loaded\n     */\n    private function setEncryptKeyWithMetadataKey(OpenPGPBackend $gpg, MetadataKey $metadataKey): OpenPGPBackend\n    {\n        // Set encryption key as the metadata key\n        try {\n            $this->assertMetadataKey($metadataKey);\n        } catch (Exception $exception) {\n            if (Configure::read('debug')) {\n                Log::error(json_encode($metadataKey));\n            }\n            $msg = __('Could not validate metadata key data.');\n            throw new InternalErrorException($msg, 500, $exception);\n        }\n        try {\n            $gpg->setEncryptKeyFromFingerprint($metadataKey->fingerprint);\n        } catch (Exception $exception) {\n            // Try to import the key in keyring again\n            try {\n                $gpg->importKeyIntoKeyring($metadataKey->armored_key);\n                $gpg->setEncryptKeyFromFingerprint($metadataKey->fingerprint);\n            } catch (Exception $exception) {\n                if (Configure::read('debug')) {\n                    Log::error(json_encode($metadataKey));\n                }\n                $msg = __('Could not import the metadata OpenPGP key.');\n                throw new InternalErrorException($msg, 500, $exception);\n            }\n        }\n\n        return $gpg;","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Metadata/src/Service/OpenPGP/OpenPGPCommonMetadataOperationsTrait.php#L29-L65","documentation":"setEncryptKeyWithMetadataKey() validates the metadata key entity via assertMetadataKey(); on failure it logs the key data (in debug) and throws an InternalErrorException with this message, chaining the original exception. It means the metadata key object is not usable for encryption (missing id, fingerprint, or armored key data).","triggerScenarios":"Any metadata encryption flow (e.g. migrateShared, metadata key rotation, resource v5 creation) passing a metadata key that fails assertMetadataKey — e.g. key entity with empty fingerprint, deleted/expired key, or malformed armored_key.","commonSituations":"Metadata key marked expired/deleted but still selected; metadata_keys row with null fingerprint after an interrupted import; passing a partially hydrated entity fetched with select() omitting required columns; test fixtures with fake key data.","solutions":["Inspect the logged JSON of the metadata key (debug mode) to see which field failed validation","Re-import the metadata key so fingerprint/armored_key are correctly populated (or fix the metadata_keys row)","Ensure the code fetches complete key entities (no select() dropping fingerprint/armored_key) and skips deleted/expired keys","Rerun the operation once the key passes assertMetadataKey"],"exampleFix":"// before: partially selected entity\n$key = $this->MetadataKeys->find()->select(['id'])->firstOrFail();\n$gpg = $this->setEncryptKeyWithMetadataKey($gpg, $key); // throws\n// after: hydrate required fields and filter unusable keys\n$key = $this->MetadataKeys->find()\n    ->where(['deleted' => false, 'fingerprint IS NOT NULL'])\n    ->firstOrFail();\n$gpg = $this->setEncryptKeyWithMetadataKey($gpg, $key);","handlingStrategy":"validation","validationCode":"$errors = (new \\Passbolt\\Metadata\\Service\\MetadataKeyAssertService())->assertMetadataKey($metadataKey);\n// or manual check:\nif (!$metadataKey->id || !$metadataKey->fingerprint || !$metadataKey->armoredKey) {\n    throw new \\LogicException('Metadata key data incomplete');\n}","typeGuard":"function isValidMetadataKey(?\\Passbolt\\Metadata\\Model\\Entity\\MetadataKey $k): bool {\n    return $k !== null\n        && $k->deleted === false\n        && is_string($k->fingerprint) && strlen($k->fingerprint) === 40\n        && is_string($k->armoredKey) && str_contains($k->armoredKey, 'PGP');\n}","tryCatchPattern":"try {\n    $gpg = $this->setEncryptKeyWithMetadataKey($gpg, $metadataKey);\n} catch (\\Cake\\Http\\Exception\\InternalErrorException $e) {\n    $root = $e->getPrevious();\n    Log::error(json_encode($metadataKey->toArray()));\n    // re-import the key into keyring, then retry\n}","preventionTips":["Enable debug mode when operating metadata migrations so the failing key data is logged","Always fetch metadata key entities with all columns (avoid select() dropping fingerprint/armored_key)","Filter out deleted/expired keys before selecting a key for encryption","Validate key data (assertMetadataKey) at ingestion time, not only at encryption time"],"tags":["metadata-key","validation","openpgp","encryption"],"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"}