Repository: spesmilo/electrum

Issue:
AssertionError: expected hex str, got <class 'str'> with len(hex_str)=88

Crash Report
============

This crash report was reported through the automatic crash reporting system 🤖

Traceback
--------------

```Python traceback
Traceback (most recent call last):
  File "app/electrum/gui/qml/qedaemon.py", line 259, in _on_backend_wallet_loaded
  File "app/electrum/wallet.py", line 3490, in unlock
  File "app/electrum/wallet.py", line 3145, in check_password
  File "app/electrum/keystore.py", line 75, in wrapper
  File "app/electrum/keystore.py", line 832, in check_password
  File "app/electrum/keystore.py", line 737, in _get_hex_seed
AssertionError: expected hex str, got <class 'str'> with len(hex_str)=88

AssertionError: expected hex str, got <class 'str'> with len(hex_str)=88
```

Reporter
------------

This issue was reported by 2 user(s):

| Electrum Version  | Python Version | Operating System  | Wallet Type  | Locale | Stack |
|---|---|---|---|---|---|
| 4.6.1  | 3.10.18 (main, Aug  5 2025, 14:02:23) [Clang 12.0.8 (https://android.googlesource.com/toolchain/llvm-project c935d99d7 | Android 15 on Xiaomi dipper (lineage_dipper-userdebug 15 BP1A.250505.005 074156d59f) |  | en_US | [ℹ](https://crashhub.electrum.org//crash/37532) | 
| 4.6.1  | 3.10.18 (main, Aug  5 2025, 14:02:23) [Clang 12.0.8 (https://android.googlesource.com/toolchain/llvm-project c935d99d7 | Android 10 on vivo PD2019 (DNN-L29 3.1.1.214(C185E2R2P2)) |  | en_US | [ℹ](https://crashhub.electrum.org//crash/37670) | 


Additional Information
------------------------


> Open app

---




Discussion:
```
>>> wallet.keystore.get_seed("1234")
'powerful random nobody notice nothing important anyway look away hidden message over'
>>> wallet.keystore._get_hex_seed("1234")
'acb740e454c3134901d7c8f16497cc1c'
>>> wallet.keystore.seed
'kUmItvyd/Ww9X4CBUdGMF5HJMJtELe4K+YiceOwsMklOq8gRkj/9yUoRJyikgrmWgi++A++BzfVXbVWl9uB29w=='
>>> len(wallet.keystore.seed)
88
```
88 is the length of an encrypted hex seed for an old keystore.

This is a regression from https://github.com/spesmilo/electrum/commit/f86bdc86a2f2cc78f12e072b1eb5ae06f40d2178.
~~`keystore.check_password` lacks unit tests.~~
```
>>> wallet.keystore.check_password(None)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "...\electrum\keystore.py", line 75, in wrapper
    return check_password_fn(self, password)
  File "...\electrum\keystore.py", line 836, in check_password
    hex_seed = self._get_hex_seed(password)
  File "...\electrum\keystore.py", line 741, in _get_hex_seed
    assert is_hex_str(hex_str), f"expected hex str, got {type(hex_str)} with {len(hex_str)=}"
AssertionError: expected hex str, got <class 'str'> with len(hex_str)=88
```
>  `keystore.check_password` lacks unit tests.

scratch that -- there are some indirect tests in
https://github.com/spesmilo/electrum/blob/392400295e733e1dd3f0cb14189466e8a76890ef/tests/test_wallet.py#L317



Patch:
diff --git a/electrum/keystore.py b/electrum/keystore.py
index 0408894c6fe8..340dcd41f55f 100644
--- a/electrum/keystore.py
+++ b/electrum/keystore.py
@@ -737,6 +737,8 @@ def watching_only_keystore(self):
         return Old_KeyStore({'mpk': self.mpk})
 
     def _get_hex_seed(self, password) -> str:
+        if not is_hex_str(self.seed) and password is None:
+            raise InvalidPassword()
         hex_str = pw_decode(self.seed, password, version=self.pw_hash_version)
         assert is_hex_str(hex_str), f"expected hex str, got {type(hex_str)} with {len(hex_str)=}"
         return hex_str


Test patch:
diff --git a/tests/test_wallet.py b/tests/test_wallet.py
index 759bcbd2873d..77ae7012aef8 100644
--- a/tests/test_wallet.py
+++ b/tests/test_wallet.py
@@ -347,6 +347,20 @@ async def test_update_password_of_standard_wallet(self):
             wallet.check_password("wrong password")
         wallet.check_password("1234")
 
+    async def test_update_password_of_standard_wallet_oldseed(self):
+        d = restore_wallet_from_text__for_unittest(
+            "powerful random nobody notice nothing important anyway look away hidden message over", path=self.wallet_path, config=self.config)
+        wallet = d['wallet']  # type: Standard_Wallet
+
+        wallet.check_password(None)
+
+        wallet.update_password(None, "1234")
+        with self.assertRaises(InvalidPassword):
+            wallet.check_password(None)
+        with self.assertRaises(InvalidPassword):
+            wallet.check_password("wrong password")
+        wallet.check_password("1234")
+
     async def test_update_password_with_app_restarts(self):
         wallet_str = '{"addr_history":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":[],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":[],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":[]},"addresses":{"change":[],"receiving":["1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr","1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6","15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA"]},"keystore":{"keypairs":{"0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5":"L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f":"L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2":"5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"},"type":"imported"},"pruned_txo":{},"seed_version":13,"stored_height":-1,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}'
         storage = WalletStorage(self.wallet_path)