{"record":{"id":"133124d7c2581d41","repo":"dani-garcia/vaultwarden","slug":"grantor-user-not-found-emergency-access","errorCode":null,"errorMessage":"Grantor user not found.","messagePattern":"Grantor user not found\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/db/models/emergency_access.rs","lineNumber":74,"sourceCode":"        if self.atype == EmergencyAccessType::View as i32 {\n            \"View\"\n        } else {\n            \"Takeover\"\n        }\n    }\n\n    pub fn to_json(&self) -> Value {\n        json!({\n            \"id\": self.uuid,\n            \"status\": self.status,\n            \"type\": self.atype,\n            \"waitTimeDays\": self.wait_time_days,\n            \"object\": \"emergencyAccess\",\n        })\n    }\n\n    pub async fn to_json_grantor_details(&self, conn: &DbConn) -> Value {\n        let grantor_user = User::find_by_uuid(&self.grantor_uuid, conn).await.expect(\"Grantor user not found.\");\n\n        json!({\n            \"id\": self.uuid,\n            \"status\": self.status,\n            \"type\": self.atype,\n            \"waitTimeDays\": self.wait_time_days,\n            \"grantorId\": grantor_user.uuid,\n            \"email\": grantor_user.email,\n            \"name\": grantor_user.name,\n            \"avatarColor\": grantor_user.avatar_color,\n            \"object\": \"emergencyAccessGrantorDetails\",\n        })\n    }\n\n    pub async fn to_json_grantee_details(&self, conn: &DbConn) -> Option<Value> {\n        let grantee_user = if let Some(grantee_uuid) = &self.grantee_uuid {\n            User::find_by_uuid(grantee_uuid, conn).await.expect(\"Grantee user not found.\")\n        } else {","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/dani-garcia/vaultwarden/blob/cc67d644f62605cb46f4d16c4a2eed1a861cc8bb/src/db/models/emergency_access.rs#L56-L92","documentation":"Panic from `.expect()` in `EmergencyAccess::to_json_grantor_details` when `User::find_by_uuid(&self.grantor_uuid)` returns None. The code assumes every emergency-access row references an existing grantor user; if that user was deleted (or the row is stale/orphaned), serialization of the emergency access JSON panics.","triggerScenarios":"Serializing an emergency_access record whose grantor user no longer exists — e.g. the grantor account was deleted/purged while the emergency_access row remained, or a manually edited/imported DB left an orphaned grantor_uuid.","commonSituations":"Admin deleting a user without cleaning up their emergency access rows; restoring a partial database backup; invitation rows left over from removed accounts when listing emergency access in the API.","solutions":["Delete the orphaned emergency_access rows referencing the missing grantor: SELECT * FROM emergency_access WHERE grantor_uuid NOT IN (SELECT uuid FROM users); then DELETE them","Restore the deleted user or their data from backup if the grantor should exist","Reproduce via the emergency access API endpoints and check which record triggers it to purge precisely that row","Harden the code to return an error/Option instead of expect() when the grantor is missing"],"exampleFix":"// before\nUser::find_by_uuid(&self.grantor_uuid, conn).await.expect(\"Grantor user not found.\")\n// after\nUser::find_by_uuid(&self.grantor_uuid, conn).await.ok_or_else(|| err!(\"Grantor user not found.\"))?","handlingStrategy":"validation","validationCode":"// before serializing, confirm the grantor exists\nSELECT 1 FROM users u JOIN emergency_access ea ON ea.grantor_uuid = u.uuid WHERE ea.uuid = ?;","typeGuard":null,"tryCatchPattern":"// Catch the panic at the API boundary and return a 404/500 with a logged orphaned-record warning\nres = catch_unwind(|| to_json_grantor_details(ea)).unwrap_or_else(|_| err_not_found());","preventionTips":["Purge emergency_access rows when deleting users (cascade cleanup)","Audit for orphaned grantor_uuid values after restores or imports","Back up before user deletions so recovery is possible","Regularly run consistency queries: emergency_access.grantor_uuid NOT IN (SELECT uuid FROM users)"],"tags":["database","referential-integrity","panic","emergency-access"],"backgroundTag":"record-not-found","analyzedSha":"cc67d644f62605cb46f4d16c4a2eed1a861cc8bb","analyzedAt":"2026-09-19T08:28:46.370Z","contentChangedAt":"2026-09-19T08:28:46.370Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}