dani-garcia/vaultwarden · warning

Grantee email does not exists

Error message

Grantee email does not exists

What it means

POST /emergency-access/invite with mail enabled: the invite is stored via EmergencyAccess::new(grantor_uuid, grantee_user.email /* String */, ...), which stores Some(email); the later new_emergency_access.email.expect("Grantee email does not exists") is therefore a defensive branch that cannot fire on this code path. If a future refactor or a pre-existing row with NULL email made it fire, the invite request would panic while sending the notification mail.

Source

Thrown at src/api/core/emergency_access.rs:266

    if EmergencyAccess::find_by_grantor_uuid_and_grantee_uuid_or_email(
        &grantor_user.uuid,
        &grantee_user.uuid,
        &grantee_user.email,
        &conn,
    )
    .await
    .is_some()
    {
        err!(format!("Grantee user already invited: {}", &grantee_user.email))
    }

    let mut new_emergency_access =
        EmergencyAccess::new(grantor_user.uuid, grantee_user.email, emergency_access_status, new_type, wait_time_days);
    new_emergency_access.save(&conn).await?;

    if CONFIG.mail_enabled() {
        mail::send_emergency_access_invite(
            &new_emergency_access.email.expect("Grantee email does not exists"),
            grantee_user.uuid,
            new_emergency_access.uuid,
            &grantor_user.name,
            &grantor_user.email,
        )
        .await?;
    } else if !new_user {
        // if mail is not enabled immediately accept the invitation for existing users
        new_emergency_access.accept_invite(&grantee_user.uuid, &email, &conn).await?;
    }

    Ok(())
}

#[post("/emergency-access/<emer_id>/reinvite")]
async fn resend_invite(emer_id: EmergencyAccessId, headers: Headers, conn: DbConn) -> EmptyResult {
    check_emergency_access_enabled()?;

View on GitHub (pinned to 0cefa4cca7)

Solutions

  1. No action needed for normal operation
  2. If auditing: verify no NULL emails with SELECT uuid FROM emergency_access WHERE email IS NULL
  3. Code hardening: replace .expect with a graceful error path

Example fix

// before
&new_emergency_access.email.expect("Grantee email does not exists"),
// after
match new_emergency_access.email.as_deref() {
    Some(email) => email,
    None => err!("Grantee email missing on emergency access invite"),
},
Defensive patterns

Strategy: validation

Validate before calling

-- Detect rows that would trip the branch (should return zero rows)
SELECT uuid, email FROM emergency_access WHERE email IS NULL OR email = '';

Prevention

When it happens

Trigger: Not reachable through the current invite flow (email is always Some here). Would require rows with NULL email from manual edits, or EmergencyAccess::new changing to accept Option<String>.

Common situations: Surfaces in static analysis / panic audits rather than production logs; NULL-email rows could only come from direct DB tampering or migration glitches.

Related errors


AI-assisted analysis of dani-garcia/vaultwarden@0cefa4cca7 (2026-08-16). Data as JSON: /api/errors/bade0ef62830eb0c. Report an issue: GitHub.