{"record":{"id":"f2477b8ab8885c7b","repo":"dani-garcia/vaultwarden","slug":"error-loading-push-devices","errorCode":null,"errorMessage":"Error loading push devices","messagePattern":"Error loading push devices","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/db/models/device.rs","lineNumber":247,"sourceCode":"\n    pub async fn find_latest_active_by_user(user_uuid: &UserId, conn: &DbConn) -> Option<Self> {\n        conn.run(move |conn| {\n            devices::table\n                .filter(devices::user_uuid.eq(user_uuid))\n                .order(devices::updated_at.desc())\n                .first::<Self>(conn)\n                .ok()\n        })\n        .await\n    }\n\n    pub async fn find_push_devices_by_user(user_uuid: &UserId, conn: &DbConn) -> Vec<Self> {\n        conn.run(move |conn| {\n            devices::table\n                .filter(devices::user_uuid.eq(user_uuid))\n                .filter(devices::push_token.is_not_null())\n                .load::<Self>(conn)\n                .expect(\"Error loading push devices\")\n        })\n        .await\n    }\n\n    pub async fn check_user_has_push_device(user_uuid: &UserId, conn: &DbConn) -> bool {\n        conn.run(move |conn| {\n            devices::table\n                .filter(devices::user_uuid.eq(user_uuid))\n                .filter(devices::push_token.is_not_null())\n                .count()\n                .first::<i64>(conn)\n                .ok()\n                .unwrap_or(0)\n                != 0\n        })\n        .await\n    }\n","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/dani-garcia/vaultwarden/blob/cc67d644f62605cb46f4d16c4a2eed1a861cc8bb/src/db/models/device.rs#L229-L265","documentation":"Panic from `.expect()` on the Diesel query in `Device::find_push_devices_by_user`, which loads a user's devices that have a non-null push_token. Any SQL failure (connection loss, schema drift, bad query) is treated as fatal and panics. Absence of push devices is NOT this error — that just yields an empty vec.","triggerScenarios":"Querying push devices for a user during a DB outage; after a migration that altered `devices` (e.g. missing `push_token` column on an older DB); stale pooled connections after a database restart.","commonSituations":"Older database upgraded to a Vaultwarden version requiring the `push_token` column; MySQL/Postgres max_connections exhausted under load; read-replica lag or failover mid-request.","solutions":["Ensure the `devices.push_token` column exists (run all pending migrations by restarting the server)","Check database availability and connection-pool settings (DB_TIMEOUT, max connections)","Fix the root Diesel error shown in the log before the panic (connectivity, permissions, missing table)","If push notifications were recently enabled, verify schema matches the new version before deploying"],"exampleFix":"// before\n.load::<Self>(conn).expect(\"Error loading push devices\")\n// after\n.load::<Self>(conn).map_err(|e| err!(DbError, \"Error loading push devices: {e}\"))","handlingStrategy":"try-catch","validationCode":"// ensure the push_token column exists on old databases\n// SELECT push_token FROM devices LIMIT 1;  (fails on pre-migration schema)","typeGuard":null,"tryCatchPattern":"// Treat DB failure as service degradation: return empty push list or 503, not a crash\nlet devices = find_push_devices().unwrap_or_default();","preventionTips":["Apply schema migrations when enabling push notifications (push_token column)","Test DB connectivity after enabling PUSH_ENABLED before traffic ramps","Watch DB connection-limit metrics under load","Keep backups of the devices table before upgrades"],"tags":["database","diesel","panic","push-notifications"],"backgroundTag":"database-query-failed","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"}