dani-garcia/vaultwarden · error

Error saving API key

Error message

Error saving API key

What it means

update_api_key backs POST /accounts/api-key and POST /accounts/rotate-api-key. After PasswordOrOtpData validation succeeds, a new API key is generated and the user row saved with user.save(&conn).await.expect("Error saving API key") — a database failure at this point panics the handler instead of returning a proper error response, so the client typically sees a 500/connection reset, and the key was generated in memory but not persisted.

Source

Thrown at src/api/core/accounts.rs:1389

    if !user.check_valid_password(&data.master_password_hash) {
        err!("Invalid password")
    }

    kdf_upgrade(&mut user, &data.master_password_hash, &conn).await?;

    Ok(Json(master_password_policy(&user, &conn).await))
}

async fn update_api_key(data: Json<PasswordOrOtpData>, rotate: bool, headers: Headers, conn: DbConn) -> JsonResult {
    let data: PasswordOrOtpData = data.into_inner();
    let mut user = headers.user;

    data.validate(&user, true, &conn).await?;

    if rotate || user.api_key.is_none() {
        user.api_key = Some(crypto::generate_api_key());
        user.save(&conn).await.expect("Error saving API key");
    }

    Ok(Json(json!({
      "apiKey": user.api_key,
      "revisionDate": format_date(&user.updated_at),
      "object": "apiKey",
    })))
}

#[post("/accounts/api-key", data = "<data>")]
async fn post_api_key(data: Json<PasswordOrOtpData>, headers: Headers, conn: DbConn) -> JsonResult {
    update_api_key(data, false, headers, conn).await
}

#[post("/accounts/rotate-api-key", data = "<data>")]
async fn rotate_api_key(data: Json<PasswordOrOtpData>, headers: Headers, conn: DbConn) -> JsonResult {
    update_api_key(data, true, headers, conn).await
}

View on GitHub (pinned to 0cefa4cca7)

Solutions

  1. Check DB health and disk space, then retry the request
  2. For SQLite: enable WAL and ensure only one instance writes the file
  3. Run pending migrations so the schema matches the binary
  4. Code fix: propagate the save error with ? instead of expect

Example fix

// before
user.save(&conn).await.expect("Error saving API key");
// after
user.save(&conn).await.map_err(|e| Error::new("Failed to save API key", e.to_string()))?;
Defensive patterns

Strategy: try-catch

Validate before calling

# Pre-flight the DB before rotating keys (sqlite example)
sqlite3 /data/db.sqlite3 'PRAGMA quick_check;' && echo db-ok

Try / catch

// Replace panic-prone expects with propagated errors in handlers
match user.save(&conn).await {
    Ok(_) => {}
    Err(e) => {
        error!("Failed to save API key for user {}: {e}", user.uuid);
        return Err(Error::new("Failed to save API key", e.to_string()));
    }
}

Prevention

When it happens

Trigger: Calling POST /api/accounts/api-key or /api/accounts/rotate-api-key when the user-row update fails: lost DB connection, SQLite 'database is locked' under concurrency, disk full, or missing migrations.

Common situations: SQLite deployments with concurrent writers and no WAL; DB restarted mid-request; disk pressure; the user row concurrently modified by another session (e.g. sync).

Related errors


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