{"record":{"id":"871c715bfd3184fe","repo":"passbolt/passbolt_api","slug":"could-not-find-the-user-data-after-save-maybe-it-has-been","errorCode":null,"errorMessage":"Could not find the user data after save. Maybe it has been deleted in the meantime.","messagePattern":"Could not find the user data after save\\. Maybe it has been deleted in the meantime\\.","errorType":"exception","errorClass":"Cake\\Http\\Exception\\InternalErrorException","httpStatus":500,"severity":"error","filePath":"src/Controller/Users/UsersEditController.php","lineNumber":127,"sourceCode":"        if (!$this->Users->save($user, $saveOptions)) {\n            throw new InternalErrorException('Could not save the user data. Please try again later.');\n        }\n\n        if ($isBeingDisabled) {\n            /** @var \\App\\Model\\Table\\SecretsTable $secretsTable */\n            $secretsTable = $this->fetchTable('Secrets');\n            $secretToExpire = $secretsTable->findByUserId($id)\n                ->select(['id', 'user_id', 'resource_id'])->all()->toArray();\n            $resourcesExpireResourcesService->expireResourcesForSecrets($secretToExpire);\n        }\n\n        // Get the updated version (ex. Role needs to be fetched again if role_id changed)\n        try {\n            /** @var \\App\\Model\\Entity\\User $user */\n            $user = $this->Users->findView($id, $this->User->role())->firstOrFail();\n        } catch (Exception $exception) {\n            $msg = __('Could not find the user data after save. Maybe it has been deleted in the meantime.');\n            throw new InternalErrorException($msg, 500, $exception);\n        }\n\n        if ($isBeingDisabled) {\n            $this->sendEmailOnUserDisable($user);\n        }\n\n        $this->sendAfterUpdateEvent($userEntityWithDirtyState);\n\n        $this->success(__('The user has been updated successfully.'), $user);\n    }\n\n    /**\n     * Validate if the user is authorized to edit the data\n     *\n     * @param array $data user data\n     * @return void\n     * @throws \\Cake\\Http\\Exception\\ForbiddenException if the user is not admin or not editing themselves\n     * @throws \\Cake\\Http\\Exception\\ForbiddenException if the user is not admin and editing role","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Controller/Users/UsersEditController.php#L109-L145","documentation":"InternalErrorException raised when re-fetching the saved user via UsersTable::findView() immediately after a successful save, and the query throws or returns no row (firstOrFail). It signals the user record became unreadable/deleted between save and re-read — an inconsistency the API surfaces as a 500 with the original exception chained.","triggerScenarios":"PUT /users/{id}.json completes save, then findView($id, role)->firstOrFail() fails: the user was deleted by a concurrent request, a findView event/behavior throws, or role-based visibility hides the row from the acting principal.","commonSituations":"Concurrent deletion by another admin during the edit; a plugin altering the findView query throwing an exception; permission/role changes mid-request (e.g. editor's own role changed) making the record invisible; DB replication lag on read replicas.","solutions":["Verify the user still exists (GET /users/{id}.json) and re-issue the edit.","Check server logs for the chained exception to see whether findView threw or simply found no row.","Look for concurrent admin operations or cron jobs deleting users during edits.","Review installed plugins that modify the Users findView query; disable suspects and retry."],"exampleFix":"// before: editing a user concurrently being deleted\nPromise.all([api.deleteUser(id), api.editUser(id, data)]);\n// after\nconst user = await api.getUser(id);\nif (user) await api.editUser(id, data);","handlingStrategy":"try-catch","validationCode":"async function userExists(api, id) { try { return !!(await api.getUser(id)); } catch { return false; } }","typeGuard":null,"tryCatchPattern":"try { await api.editUser(id, data); } catch (e) { if (e.code === 500 && /deleted in the meantime/.test(e.message)) { await refreshUserList(); } else { throw e; } }","preventionTips":["Avoid concurrent edit/delete operations on the same user.","Re-check the user exists right before editing in automated scripts.","Investigate plugins that modify the Users find query if this recurs."],"tags":["race-condition","read-after-write","internal-error","http-500"],"backgroundTag":"entity-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"}