passbolt/passbolt_api · critical · Cake\Http\Exception\InternalErrorException

Invalid record set. Responses should be set for approved…

Error message

Invalid record set. Responses should be set for approved requests.

What it means

InternalErrorException (HTTP 500) from decorateResults: the request is approved, so an account_recovery_private_keys row containing the wrapped organization/private key data must exist for the requesting user, but the lookup returned nothing. This signals a data-integrity violation rather than a client mistake.

Solutions

  1. Restore/recreate the user's account_recovery_private_keys row (re-run account recovery setup for that user)
  2. Check DB integrity: user has account_recovery_user_settings + private key rows consistent with the approved request
  3. Report to server admins — indicates corrupted account recovery state; inspect server logs for the underlying RecordNotFoundException

Example fix

// before
// approved request but no account_recovery_private_keys row for user -> 500
// after
re-enroll user in account recovery so a private key row exists, or reject/delete the orphaned request
Defensive patterns

Strategy: try-catch

Validate before calling

$hasKey = $this->AccountRecoveryPrivateKeys->exists(['user_id' => $userId]); if (!$hasKey && $request->isApproved()) { // surface data-integrity problem to admins before calling }

Type guard

null

Try / catch

try { $service->decorateResults($request); } catch (InternalErrorException $e) { logCriticalDataIntegrityIssue($request->id); alertAdmin(); }

Prevention

When it happens

Trigger: decorateResults() on an approved request where AccountRecoveryPrivateKeys->find()->where(['user_id' => $requestEntity->user_id])->firstOrFail() finds no private key row for the user.

Common situations: Orphaned approved request after user data was deleted or a failed/partial enrollment; manual DB cleanup removed key rows; migration/upgrade left inconsistent account recovery data.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at plugins/PassboltEe/AccountRecovery/src/Service/AccountRecoveryRequests/AccountRecoveryRequestGetService.php:217

            'modified' => $requestEntity->modified,
            'modified_by' => $requestEntity->modified_by,
            'status' => $requestEntity->status,
            // Not needed
            //'armored_key' => $requestEntity->armored_key,
        ];

        if ($requestEntity->isApproved()) {
            $errorMsg = 'Invalid record set. Responses should be set for approved requests.';

            // There should be private key available
            try {
                /** @var \Passbolt\AccountRecovery\Model\Entity\AccountRecoveryPrivateKey $privateKeyEntity */
                $privateKeyEntity = $this->AccountRecoveryPrivateKeys->find()
                    ->select('data')
                    ->where(['user_id' => $requestEntity->user_id])
                    ->firstOrFail();
            } catch (RecordNotFoundException $exception) {
                throw new InternalErrorException($errorMsg, 500, $exception);
            }
            $data['account_recovery_private_key']['data'] = $privateKeyEntity->data;

            // There should be at least one response
            $responses = $this->AccountRecoveryResponses->find()
                ->select([
                    'account_recovery_request_id',
                    'status',
                    'responder_foreign_model',
                    'responder_foreign_key',
                    'data',
                ])
                ->where(['account_recovery_request_id' => $requestEntity->id])
                ->all()
                ->toArray();
            if (empty($responses)) {
                throw new InternalErrorException($errorMsg);
            }

View on GitHub (pinned to 31c1bbc10f)