dani-garcia/vaultwarden · error

Error loading emergency_access

Error message

Error loading emergency_access

What it means

Panic from `.expect()` on the Diesel query in `EmergencyAccess::find_all_recoveries_initiated`, which loads all emergency_access rows in RecoveryInitiated status. Any SQL failure (connection loss, missing table/column, permissions) is fatal and panics instead of returning an empty vec or error.

Solutions

  1. Verify database connectivity and that the `emergency_access` table/status column exist (run pending migrations)
  2. Read the underlying Diesel error in the logs above the panic and fix that cause
  3. Check DB user permissions (SELECT on emergency_access) and disk space for SQLite
  4. Restart the server to reset the connection pool after a DB outage

Example fix

// before
.load::<Self>(conn).expect("Error loading emergency_access")
// after
.load::<Self>(conn).map_err(|e| err!(DbError, "Error loading emergency_access: {e}"))
Defensive patterns

Strategy: try-catch

Validate before calling

// verify emergency_access table is queryable before running recovery jobs
// SELECT 1 FROM emergency_access LIMIT 1;

Try / catch

// Wrap the scheduled recovery scan so a DB failure logs and retries instead of crashing
if let Err(e) = run_recovery_scan() { log_error(e); schedule_retry(); }

Prevention

When it happens

Trigger: The periodic emergency-access recovery job or an API call listing initiated recoveries runs while the DB is unreachable, after a failed migration on the `emergency_access` table, or with corrupt/locked SQLite data.

Common situations: Upgrades where the emergency_access schema wasn't migrated; database restarted under load leaving stale pool connections; disk-full or locked SQLite file on nightly cron jobs.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of dani-garcia/vaultwarden@cc67d644f6 (2026-09-19). Data as JSON: /api/errors/d559fc12a8ce5a45. Report an issue: GitHub.

Appendix: source

Thrown at src/db/models/emergency_access.rs:263

        conn: &DbConn,
    ) -> Option<Self> {
        conn.run(move |conn| {
            emergency_access::table
                .filter(emergency_access::grantor_uuid.eq(grantor_uuid))
                .filter(emergency_access::grantee_uuid.eq(grantee_uuid).or(emergency_access::email.eq(email)))
                .first::<Self>(conn)
                .ok()
        })
        .await
    }

    pub async fn find_all_recoveries_initiated(conn: &DbConn) -> Vec<Self> {
        conn.run(move |conn| {
            emergency_access::table
                .filter(emergency_access::status.eq(EmergencyAccessStatus::RecoveryInitiated as i32))
                .filter(emergency_access::recovery_initiated_at.is_not_null())
                .load::<Self>(conn)
                .expect("Error loading emergency_access")
        })
        .await
    }

    pub async fn find_by_uuid_and_grantor_uuid(
        uuid: &EmergencyAccessId,
        grantor_uuid: &UserId,
        conn: &DbConn,
    ) -> Option<Self> {
        conn.run(move |conn| {
            emergency_access::table
                .filter(emergency_access::uuid.eq(uuid))
                .filter(emergency_access::grantor_uuid.eq(grantor_uuid))
                .first::<Self>(conn)
                .ok()
        })
        .await
    }

View on GitHub (pinned to cc67d644f6)