remove the terminal saving and loading dialogs and show an error when saving a new wallet or opening a wallet fails
What changed, and why it matters
This commit fixes several small but real bugs in Sparrow Wallet's terminal (command-line) interface. It prevents the app from crashing with a NullPointerException when an error message is missing, makes sure password memory is wiped even when wallet opening fails, and ensures loading/saving dialogs close properly when errors occur. These are reliability and minor security-hygiene fixes rather than a major vulnerability patch.
No urgent action required. Users running the terminal version of Sparrow Wallet should update to a release containing this commit for improved error handling and password-memory hygiene. Developers should review other terminal wallet dialogs for similar missing error handling or stuck-modal issues.
Security signals we found
NullPointerException avoided on exception message handling
Password SecureString now cleared on both success and failure paths
Terminal loading/saving dialogs no longer remain open after errors
Error dialogs now shown to user on terminal save/open failures
Evidence from the diff
The diff makes three categories of changes: (1) adds null checks before calling startsWith() on exception messages in both the GUI and terminal open-wallet paths, avoiding a NullPointerException when e.getMessage() is null; (2) moves password.clear() outside the success branch so the SecureString is cleared even when loading fails, and adds securePassword.clear() in the terminal load failure handler; (3) removes stuck ‘saving’/’loading’ terminal dialogs and shows error dialogs when wallet save/open operations fail. The password-clearing change is a defensive memory-hygiene improvement; the null-message change is a robustness fix; the dialog cleanup is a UX/reliability fix.
Changed components
src/main/java/com/sparrowwallet/sparrow/AppController.javasrc/main/java/com/sparrowwallet/sparrow/terminal/wallet/LoadWallet.javasrc/main/java/com/sparrowwallet/sparrow/terminal/wallet/NewWalletDialog.javaInspect captured patch +11 / −4
### src/main/java/com/sparrowwallet/sparrow/AppController.java
@@ -1242,14 +1242,14 @@ public void openWalletFile(File file, boolean forceSameWindow) {
log.error("Error Opening Wallet", exception);
showErrorDialog("Error Opening Wallet", exception.getMessage() == null || exception.getMessage().contains("Expected BEGIN_OBJECT") ? "Unsupported wallet file format." : exception.getMessage());
}
- password.clear();
}
+ password.clear();
});
EventManager.get().post(new StorageEvent(storage.getWalletId(null), TimedEvent.Action.START, "Decrypting wallet..."));
loadWalletService.start();
}
} catch(Exception e) {
- if(e instanceof IOException && e.getMessage().startsWith("The process cannot access the file because another process has locked")) {
+ if(e instanceof IOException && e.getMessage() != null && e.getMessage().startsWith("The process cannot access the file because another process has locked")) {
log.error("Error opening wallet", e);
showErrorDialog("Error Opening Wallet", "The wallet file is locked. Is another instance of " + SparrowWallet.APP_NAME + " already running?");
} else if(!attemptImportWallet(file, null)) {
### src/main/java/com/sparrowwallet/sparrow/terminal/wallet/LoadWallet.java
@@ -68,13 +68,15 @@ public void run() {
}
Platform.runLater(() -> {
- Storage.LoadWalletService loadWalletService = new Storage.LoadWalletService(storage, new SecureString(password));
+ SecureString securePassword = new SecureString(password);
+ Storage.LoadWalletService loadWalletService = new Storage.LoadWalletService(storage, securePassword);
loadWalletService.setOnSucceeded(workerStateEvent -> {
EventManager.get().post(new StorageEvent(storage.getWalletId(null), TimedEvent.Action.END, "Done"));
WalletAndKey walletAndKey = loadWalletService.getValue();
openWallet(storage, walletAndKey);
});
loadWalletService.setOnFailed(workerStateEvent -> {
+ securePassword.clear();
EventManager.get().post(new StorageEvent(storage.getWalletId(null), TimedEvent.Action.END, "Failed"));
SparrowTerminal.get().getGuiThread().invokeLater(() -> SparrowTerminal.get().getGui().removeWindow(loadingDialog));
Throwable exception = loadWalletService.getException();
@@ -94,7 +96,8 @@ public void run() {
});
}
} catch(Exception e) {
- if(e instanceof IOException && e.getMessage().startsWith("The process cannot access the file because another process has locked")) {
+ SparrowTerminal.get().getGuiThread().invokeLater(() -> SparrowTerminal.get().getGui().removeWindow(loadingDialog));
+ if(e instanceof IOException && e.getMessage() != null && e.getMessage().startsWith("The process cannot access the file because another process has locked")) {
showErrorDialog("Error Opening Wallet", "The wallet file is locked. Is another instance of " + SparrowWallet.APP_NAME + " already running?");
} else {
log.error("Error opening wallet", e);
### src/main/java/com/sparrowwallet/sparrow/terminal/wallet/NewWalletDialog.java
@@ -150,6 +150,8 @@ private void saveWallet(Wallet wallet) {
});
} catch(IOException | StorageException | MnemonicException e) {
log.error("Error saving imported wallet", e);
+ SparrowTerminal.get().getGuiThread().invokeLater(() -> SparrowTerminal.get().getGui().removeWindow(savingDialog));
+ showErrorDialog("Error Saving Wallet", e.getMessage());
}
} else {
Storage.KeyDerivationService keyDerivationService = new Storage.KeyDerivationService(storage, new SecureString(password));
@@ -182,6 +184,8 @@ private void saveWallet(Wallet wallet) {
});
} catch(IOException | StorageException | MnemonicException e) {
log.error("Error saving imported wallet", e);
+ SparrowTerminal.get().getGuiThread().invokeLater(() -> SparrowTerminal.get().getGui().removeWindow(savingDialog));
+ showErrorDialog("Error Saving Wallet", e.getMessage());
} finally {
if(key != null) {
key.clear();Why this scored 37/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.