{"record":{"id":"e4f4509381bbcd5a","repo":"passbolt/passbolt_api","slug":"the-user-metadata-session-keys-could-not-be-deleted","errorCode":null,"errorMessage":"The user metadata session keys could not be deleted.","messagePattern":"The user metadata session keys could not be deleted\\.","errorType":"http","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltCe/Metadata/src/Service/UserMetadataKeysDeleteService.php","lineNumber":95,"sourceCode":"    private function deleteMetadataSessionKeys(string $userId): void\n    {\n        /** @var \\Passbolt\\Metadata\\Model\\Table\\MetadataSessionKeysTable $metadataSessionKeysTable */\n        $metadataSessionKeysTable = $this->fetchTable('Passbolt/Metadata.MetadataSessionKeys');\n\n        $metadataSessionKeys = $metadataSessionKeysTable\n            ->unhydratedFind()\n            ->select(['id'])\n            ->where(['user_id' => $userId])\n            ->toArray();\n        if (empty($metadataSessionKeys)) {\n            // Nothing to delete\n            return;\n        }\n\n        $metadataPrivateKeysIds = Hash::extract($metadataSessionKeys, '{n}.id');\n        $result = $metadataSessionKeysTable->deleteAll(['id IN' => $metadataPrivateKeysIds]);\n        if ($result <= 0) {\n            throw new InternalErrorException(__('The user metadata session keys could not be deleted.'));\n        }\n    }\n}\n","sourceCodeStart":77,"sourceCodeEnd":99,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Metadata/src/Service/UserMetadataKeysDeleteService.php#L77-L99","documentation":"This InternalErrorException is thrown by deleteMetadataSessionKeys when deleteAll on the user's metadata session keys removes zero rows. The service treats a no-op delete as a failure so the caller knows the user's metadata session key cleanup did not happen.","triggerScenarios":"Calling delete() on UserMetadataKeysDeleteService where $metadataSessionKeys entities were passed but their ids no longer match rows in the metadata session keys table (concurrent deletion, stale entities), or extracted ids are empty/invalid so the IN clause matches nothing.","commonSituations":"Two cleanup processes racing on the same user; entities fetched before another request already deleted the session keys; wrong table/entity passed so ids don't exist in that table.","solutions":["Ensure the session key entities are freshly loaded and ids are present before calling delete()","Check for concurrent deletions of the same user's metadata session keys","Confirm the ids exist in the metadata session keys table at the time of deleteAll","Return early (or treat as success) when the extracted id list is empty, mirroring the upstream guard"],"exampleFix":"// before\n$metadataPrivateKeysIds = Hash::extract($metadataSessionKeys, '{n}.id');\n$result = $metadataSessionKeysTable->deleteAll(['id IN' => $metadataPrivateKeysIds]);\nif ($result <= 0) {\n    throw new InternalErrorException(__('The user metadata session keys could not be deleted.'));\n}\n// after\n$metadataSessionKeysIds = Hash::extract($metadataSessionKeys, '{n}.id');\nif (empty($metadataSessionKeysIds)) {\n    return;\n}\n$result = $metadataSessionKeysTable->deleteAll(['id IN' => $metadataSessionKeysIds]);\nif ($result <= 0) {\n    throw new InternalErrorException(__('The user metadata session keys could not be deleted.'));\n}","handlingStrategy":"try-catch","validationCode":"$ids = Hash::extract($metadataSessionKeys, '{n}.id');\nif (!empty($ids) && TableRegistry::getTableLocator()->get('MetadataSessionKeys')->exists(['id IN' => $ids])) {\n    // safe to delete\n}","typeGuard":"function sessionKeysDeletable(array $entities): bool {\n    $ids = Hash::extract($entities, '{n}.id');\n    return !empty($ids) && array_reduce($ids, fn($ok, $id) => $ok && is_string($id) && Validation::uuid($id), true);\n}","tryCatchPattern":"try {\n    $service->delete($user);\n} catch (InternalErrorException $e) {\n    // verify rows already deleted; treat as idempotent success if so\n    $this->log($e->getMessage(), 'error');\n}","preventionTips":["Fetch session key entities and delete within one transaction","Handle the already-deleted case as success to stay idempotent","Avoid parallel jobs deleting the same user's session keys","Note the copied variable name ($metadataPrivateKeysIds) in the source; use a clear name in your own code"],"tags":["database","delete","internal-error","cakephp"],"backgroundTag":"database-write-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"}