dani-garcia/vaultwarden · error
Unable to update emergency access notification date
Error message
Unable to update emergency access notification date
What it means
emergency_notification_reminder_job: one day before a recovery activates, it records the notification via update_last_notification_date_and_save(&now, &conn).expect("Unable to update emergency access notification date"). A DB failure panics the reminder job task. The code deliberately updates a narrow column to avoid races with the timeout job, so the realistic cause is DB unavailability rather than row conflicts.
Source
Thrown at src/api/core/emergency_access.rs:807
let now = Utc::now().naive_utc();
for mut emer in emergency_access_list {
// The find_all_recoveries_initiated already checks if the recovery_initiated_at is not null (None)
// Calculate the day before the recovery will become active
let final_recovery_reminder_at =
emer.recovery_initiated_at.unwrap() + TimeDelta::try_days(i64::from(emer.wait_time_days - 1)).unwrap();
// Calculate if a day has passed since the previous notification, else no notification has been sent before
let next_recovery_reminder_at = if let Some(last_notification_at) = emer.last_notification_at {
last_notification_at + TimeDelta::try_days(1).unwrap()
} else {
now
};
if final_recovery_reminder_at.le(&now) && next_recovery_reminder_at.le(&now) {
// Only update the last notification date
// Updating the whole record could cause issues when the emergency_request_timeout_job is also active
emer.update_last_notification_date_and_save(&now, &conn)
.await
.expect("Unable to update emergency access notification date");
if CONFIG.mail_enabled() {
// get grantor user to send Accepted email
let grantor_user =
User::find_by_uuid(&emer.grantor_uuid, &conn).await.expect("Grantor user not found");
// get grantee user to send Accepted email
let grantee_user =
User::find_by_uuid(&emer.grantee_uuid.clone().expect("Grantee user invalid"), &conn)
.await
.expect("Grantee user not found");
mail::send_emergency_access_recovery_reminder(
&grantor_user.email,
&grantee_user.name,
emer.get_type_as_str(),
"1", // This notification is only triggered one day before the activation
)View on GitHub (pinned to 0cefa4cca7)
Solutions
- Restore DB health and restart the service to respawn the job
- Reduce write contention (WAL for SQLite, fewer concurrent jobs)
- Verify last_notification_at afterwards to avoid duplicate reminder mails on rerun
- Code fix: log-and-continue per row instead of expect
Example fix
// before
emer.update_last_notification_date_and_save(&now, &conn).await.expect("Unable to update emergency access notification date");
// after
if let Err(e) = emer.update_last_notification_date_and_save(&now, &conn).await {
error!("Failed to record reminder for emergency access {}: {e}", emer.uuid);
continue;
} Defensive patterns
Strategy: try-catch
Validate before calling
-- Rows the reminder job will process; confirm they look healthy first SELECT uuid, grantor_uuid, grantee_uuid, wait_time_days, recovery_initiated_at, last_notification_at FROM emergency_access WHERE recovery_initiated_at IS NOT NULL;
Try / catch
if let Err(e) = emer.update_last_notification_date_and_save(&now, &conn).await {
error!("reminder job: failed to record notification for {}: {e}", emer.uuid);
continue;
} Prevention
- Keep the DB healthy at reminder intervals
- After incidents, check last_notification_at to avoid duplicate reminders
- Prefer narrow-column updates (as the code does) over whole-row saves to avoid job races
When it happens
Trigger: The reminder job firing during DB unavailability or lock contention while updating last_notification_at for a due recovery.
Common situations: SQLite lock contention; DB failover at job time; disk full — the same conditions that break the other job writes.
Related errors
- Unable to update emergency access status
- Grantee user should exist but does not!
- Grantor user not found
- Grantee user invalid
- Grantee user not found
AI-assisted analysis of dani-garcia/vaultwarden@0cefa4cca7 (2026-08-16).
Data as JSON: /api/errors/097d37c5f8ae9845.
Report an issue: GitHub.