{"record":{"id":"7e1f5499131ddd11","repo":"stalwartlabs/stalwart","slug":"failed-to-delete-keys","errorCode":null,"errorMessage":"Failed to delete keys","messagePattern":"Failed to delete keys","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/common/src/manager/console.rs","lineNumber":137,"sourceCode":"                                },\n                            )\n                            .await\n                            .expect(\"Failed to scan keys\");\n\n                        if total > 0 {\n                            print!(\"Are you sure you want to delete {total} keys? (y/N): \");\n                            io::stdout().flush().unwrap();\n                            let mut response = String::new();\n                            io::stdin().read_line(&mut response).unwrap();\n                            if !response.trim().eq_ignore_ascii_case(\"y\") {\n                                println!(\"Aborted.\");\n                                return;\n                            }\n\n                            store\n                                .delete_range(from_key, to_key)\n                                .await\n                                .expect(\"Failed to delete keys\");\n                            println!(\"Deleted {total} keys.\");\n                        } else {\n                            println!(\"No keys found.\");\n                        }\n                    }\n                }\n                (Some(key), None) => {\n                    if let Some(key) = parse_key(key) {\n                        println!(\"Deleting key: {:?}\", key);\n                        let mut key = key.into_iter();\n                        let mut batch = BatchBuilder::new();\n                        batch.clear(ValueClass::Any(AnyClass {\n                            subspace: key.next().unwrap(),\n                            key: key.collect(),\n                        }));\n                        if let Err(err) = store.write(batch.build_all()).await {\n                            println!(\"Failed to delete key: {}\", err);\n                        }","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/stalwartlabs/stalwart/blob/e96200385781a6a9995a8b839ac27d6c75a983ee/crates/common/src/manager/console.rs#L119-L155","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// verify write access before confirming deletion\n// e.g. ensure the store is not read-only and credentials permit deletes\nif matches!(store, Store::None) {\n    eprintln!(\"No store available. Verify your configuration.\");\n    return;\n}","typeGuard":null,"tryCatchPattern":"match store.delete_range(from_key, to_key).await {\n    Ok(()) => println!(\"Deleted {total} keys.\"),\n    Err(err) => eprintln!(\"Failed to delete keys: {}\", err), // keep console alive instead of .expect\n}","preventionTips":["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."],"tags":["database","storage","console","key-deletion","panic"],"backgroundTag":"database-write-failed","analyzedSha":"e96200385781a6a9995a8b839ac27d6c75a983ee","analyzedAt":"2026-09-06T22:07:17.982Z","contentChangedAt":"2026-09-06T22:07:17.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}