{"record":{"id":"13e9eec61d7b8e5b","repo":"passbolt/passbolt_api","slug":"the-metadata-key-has-already-been-deleted-13e9ee","errorCode":null,"errorMessage":"The metadata key has already been deleted.","messagePattern":"The metadata key has already been deleted\\.","errorType":"http","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"plugins/PassboltCe/Metadata/src/Service/MetadataKey/MetadataKeyUpdateService.php","lineNumber":72,"sourceCode":"\n        $metadataKeysTable = $this->fetchTable('Passbolt/Metadata.MetadataKeys');\n\n        // Assert the key exist\n        try {\n            /** @var \\Passbolt\\Metadata\\Model\\Entity\\MetadataKey $metadataKey */\n            $metadataKey = $metadataKeysTable->get($id);\n        } catch (RecordNotFoundException $exception) { // @phpstan-ignore-line\n            throw new NotFoundException(__('The metadata key does not exist or has been deleted.'), 404, $exception);\n        }\n\n        // Assert fingerprint is the same\n        if ($metadataKey->fingerprint !== $dto->fingerprint) {\n            throw new NotFoundException(__('The metadata key fingerprint is invalid.'));\n        }\n\n        // Assert the key is not already deleted\n        if ($metadataKey->isDeleted()) {\n            throw new NotFoundException(__('The metadata key has already been deleted.'));\n        }\n\n        // Assert they key was not previously marked as expired\n        if ($metadataKey->isExpired()) {\n            throw new BadRequestException(__('The metadata key is already marked as expired.'));\n        }\n\n        // Patch the key deleted field with the current time\n        $options = [\n            'accessibleFields' => [\n                'fingerprint' => true, 'armored_key' => true, 'expired' => true, 'modified_by' => true,\n            ],\n            'validate' => 'update',\n        ];\n        $patch = [\n            'fingerprint' => $dto->fingerprint,\n            'armored_key' => $dto->armoredKey,\n            'expired' => $dto->expired,","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Metadata/src/Service/MetadataKey/MetadataKeyUpdateService.php#L54-L90","documentation":"MetadataKeyUpdateService::update() throws a NotFoundException when the target metadata key's deleted flag is set. Once a key is soft-deleted it is immutable, so any further update (e.g. marking it expired) is refused. The 404-style message intentionally hides the deleted state distinction from unauthorized callers.","triggerScenarios":"Calling PUT /metadata/keys/{id} (update) on a metadata key whose entity returns isDeleted() === true, e.g. re-expiring or re-arming an already deleted key.","commonSituations":"Client cached a stale key id after another admin deleted the key; replaying an update request twice; UI not refreshed after a deletion.","solutions":["Check the key's deleted flag (GET /metadata/keys) before attempting any update","If the key must exist, recreate it via the metadata key create endpoint instead of updating the deleted one","Remove the duplicate/stale update request from the client workflow","If deletion was a mistake, restore the key's deleted field via an allowed flow rather than update()"],"exampleFix":"// before\n$service->update($uac, $keyId, $dto); // throws if key deleted\n// after\n$key = $keysTable->get($keyId);\nif (!$key->isDeleted()) {\n    $service->update($uac, $keyId, $dto);\n}","handlingStrategy":"validation","validationCode":"$key = $metadataKeysTable->find()->where(['id' => $keyId])->first();\nif ($key === null || $key->isDeleted()) {\n    return; // skip update for deleted keys\n}","typeGuard":"$isUpdatable = fn (MetadataKey $k): bool => !$k->isDeleted() && !$k->isExpired();","tryCatchPattern":"try {\n    $service->update($uac, $keyId, $dto);\n} catch (NotFoundException $e) {\n    // key deleted or missing: refresh local cache of metadata keys\n}","preventionTips":["Always GET the key state before updating","Refresh client-side key cache after any deletion","Treat deleted metadata keys as immutable in client logic"],"tags":["metadata","not-found","deleted-entity"],"backgroundTag":"resource-not-found","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"}