passbolt/passbolt_api · error · InternalErrorException

The user metadata session keys could not be deleted.

Error message

The user metadata session keys could not be deleted.

What it means

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.

Solutions

  1. Ensure the session key entities are freshly loaded and ids are present before calling delete()
  2. Check for concurrent deletions of the same user's metadata session keys
  3. Confirm the ids exist in the metadata session keys table at the time of deleteAll
  4. Return early (or treat as success) when the extracted id list is empty, mirroring the upstream guard

Example fix

// before
$metadataPrivateKeysIds = Hash::extract($metadataSessionKeys, '{n}.id');
$result = $metadataSessionKeysTable->deleteAll(['id IN' => $metadataPrivateKeysIds]);
if ($result <= 0) {
    throw new InternalErrorException(__('The user metadata session keys could not be deleted.'));
}
// after
$metadataSessionKeysIds = Hash::extract($metadataSessionKeys, '{n}.id');
if (empty($metadataSessionKeysIds)) {
    return;
}
$result = $metadataSessionKeysTable->deleteAll(['id IN' => $metadataSessionKeysIds]);
if ($result <= 0) {
    throw new InternalErrorException(__('The user metadata session keys could not be deleted.'));
}
Defensive patterns

Strategy: try-catch

Validate before calling

$ids = Hash::extract($metadataSessionKeys, '{n}.id');
if (!empty($ids) && TableRegistry::getTableLocator()->get('MetadataSessionKeys')->exists(['id IN' => $ids])) {
    // safe to delete
}

Type guard

function sessionKeysDeletable(array $entities): bool {
    $ids = Hash::extract($entities, '{n}.id');
    return !empty($ids) && array_reduce($ids, fn($ok, $id) => $ok && is_string($id) && Validation::uuid($id), true);
}

Try / catch

try {
    $service->delete($user);
} catch (InternalErrorException $e) {
    // verify rows already deleted; treat as idempotent success if so
    $this->log($e->getMessage(), 'error');
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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

Appendix: source

Thrown at plugins/PassboltCe/Metadata/src/Service/UserMetadataKeysDeleteService.php:95

    private function deleteMetadataSessionKeys(string $userId): void
    {
        /** @var \Passbolt\Metadata\Model\Table\MetadataSessionKeysTable $metadataSessionKeysTable */
        $metadataSessionKeysTable = $this->fetchTable('Passbolt/Metadata.MetadataSessionKeys');

        $metadataSessionKeys = $metadataSessionKeysTable
            ->unhydratedFind()
            ->select(['id'])
            ->where(['user_id' => $userId])
            ->toArray();
        if (empty($metadataSessionKeys)) {
            // Nothing to delete
            return;
        }

        $metadataPrivateKeysIds = Hash::extract($metadataSessionKeys, '{n}.id');
        $result = $metadataSessionKeysTable->deleteAll(['id IN' => $metadataPrivateKeysIds]);
        if ($result <= 0) {
            throw new InternalErrorException(__('The user metadata session keys could not be deleted.'));
        }
    }
}

View on GitHub (pinned to 31c1bbc10f)