stalwartlabs/stalwart · error
Failed to delete keys
Error message
Failed to delete keys
What it means
This panic comes from `store.delete_range(from_key, to_key).await.expect("Failed to delete keys")` in `store_console`'s `delete <from_key> <to_key>` command. The count succeeded and the user confirmed, but the actual batch deletion write against the store backend failed, so `expect` panics and the console process aborts.
Source
Thrown at crates/common/src/manager/console.rs:137
},
)
.await
.expect("Failed to scan keys");
if total > 0 {
print!("Are you sure you want to delete {total} keys? (y/N): ");
io::stdout().flush().unwrap();
let mut response = String::new();
io::stdin().read_line(&mut response).unwrap();
if !response.trim().eq_ignore_ascii_case("y") {
println!("Aborted.");
return;
}
store
.delete_range(from_key, to_key)
.await
.expect("Failed to delete keys");
println!("Deleted {total} keys.");
} else {
println!("No keys found.");
}
}
}
(Some(key), None) => {
if let Some(key) = parse_key(key) {
println!("Deleting key: {:?}", key);
let mut key = key.into_iter();
let mut batch = BatchBuilder::new();
batch.clear(ValueClass::Any(AnyClass {
subspace: key.next().unwrap(),
key: key.collect(),
}));
if let Err(err) = store.write(batch.build_all()).await {
println!("Failed to delete key: {}", err);
}View on GitHub (pinned to e962003857)
Solutions
- Check whether the failure is transient (connection blip) and re-run the command; the wrapped backend error in the panic message names the cause.
- Reduce the key range and delete in smaller chunks to stay within backend transaction/batch size limits.
- Verify the store user has write/delete privileges and the backend is not a read-only replica.
- If range deletes keep failing at the driver level, list keys with `scan` and delete them individually with `delete <key>`, which reports errors non-fatally.
Defensive patterns
Strategy: try-catch
Validate before calling
// verify write access before confirming deletion
// e.g. ensure the store is not read-only and credentials permit deletes
if matches!(store, Store::None) {
eprintln!("No store available. Verify your configuration.");
return;
} Try / catch
match store.delete_range(from_key, to_key).await {
Ok(()) => println!("Deleted {total} keys."),
Err(err) => eprintln!("Failed to delete keys: {}", err), // keep console alive instead of .expect
} Prevention
- Ensure the DB user has delete privileges and the target is not a read-only replica.
- Delete large ranges in smaller chunks to respect backend transaction size limits.
- Re-check connectivity right before confirming; long sessions can drop connections.
- Fall back to per-key `delete <key>` (which reports errors non-fatally) when range deletes fail.
When it happens
Trigger: Running `delete <from_key> <to_key>` and answering "y" to the confirmation prompt, then the backend write fails: DB connection lost between the count and the delete, write rejected by the backend (read-only replica, permissions, transaction too large), driver error committing the delete batch.
Common situations: Long-lived console sessions whose DB connection timed out before the delete; attempting deletes against a read-only database replica; deleting a huge key range exceeding backend transaction/batch size limits (e.g. FoundationDB or MySQL packet limits); insufficient DB user privileges to delete rows.
Related errors
- Failed to scan keys
- Migration aborted: {message}
- Failed to decode base64
- unwrap_tls called on non-TLS acceptor
- Unknown database schema version, expected {} or below, found
AI-assisted analysis of stalwartlabs/stalwart@e962003857 (2026-09-06).
Data as JSON: /api/errors/7e1f5499131ddd11.
Report an issue: GitHub.