Is there an existing issue for this?
- I have searched the existing issues
Current behaviour
importdescriptors RPC is intended to be best-effort: each item in the batch either succeeds or returns its own error in result[i].error. But if an item has an invalid or missing timestamp field, the whole RPC throws and you lose the response that was being built. Items processed before the throwing item are already committed to the wallet. The caller has no way to know which ones failed or passed, because the result array is discarded.
desc-missing, malformed descriptor, etc. all correctly land in the per-item result via catch. Timestamp validation is the odd one out.
Expected behaviour
To not throw the whole RPC but only to fill in result[i].error for the invalid timestamp item and continue processing the remaining items, matching how desc-missing and other validation failures already behave.
Steps to reproduce
Using the Python functional test framework:
#!/usr/bin/env python3
from test_framework.descriptors import descsum_create
from test_framework.test_framework import BitcoinTestFramework
from test_framework.wallet_util import get_generate_key
class ImportDescriptorsBatchBug(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def run_test(self):
self.nodes[0].createwallet(wallet_name='w', disable_private_keys=False, blank=True)
w = self.nodes[0].get_wallet_rpc("w")
d1 = descsum_create("wpkh(" + get_generate_key().privkey + ")")
d2 = descsum_create("wpkh(" + get_generate_key().privkey + ")")
d3 = descsum_create("wpkh(" + get_generate_key().privkey + ")")
# Middle item is missing "timestamp".
# Expected (per the per-item error contract): result array of length 3,
# with result[1].error populated and items 0 and 2 succeeding.
# Actual: top-level RPC throw, no result array, item 0 applied, item 2 skipped.
try:
result = w.importdescriptors([
{"desc": d1, "timestamp": "now"},
{"desc": d2},
{"desc": d3, "timestamp": "now"},
])
self.log.info("result: %s", result)
except Exception as e:
self.log.info("RPC threw instead of returning per-item errors: %s", e)
self.log.info("descriptors actually in wallet:")
for d in w.listdescriptors()["descriptors"]:
self.log.info(" %s", d["desc"])
if __name__ == "__main__":
ImportDescriptorsBatchBug(__file__).main()
Logs:
2026-04-30T14:07:30.458736Z TestFramework (INFO): PRNG seed is: 782373921116581945
2026-04-30T14:07:30.509319Z TestFramework (INFO): Initializing test directory /tmp/bitcoin_func_test_yktyf2im
2026-04-30T14:07:30.803708Z TestFramework (INFO): RPC threw instead of returning per-item errors: {'code': -3, 'message': 'Missing required timestamp field for key'} [http_status=200]
2026-04-30T14:07:30.803815Z TestFramework (INFO): descriptors actually in wallet:
2026-04-30T14:07:30.804360Z TestFramework (INFO): wpkh(028584a0dc8ec35608360c90fc39206050780ee43ee8659598bd7fabe454c70063)#lf98x889
2026-04-30T14:07:30.854894Z TestFramework (INFO): Stopping nodes
2026-04-30T14:07:30.957905Z TestFramework (INFO): Cleaning up /tmp/bitcoin_func_test_yktyf2im on exit
2026-04-30T14:07:30.958057Z TestFramework (INFO): Tests successful
Relevant log output
No response
How did you obtain Bitcoin Core
Compiled from source
What version of Bitcoin Core are you using?
Bitcoin Core daemon version v31.0.0 bitcoind
Operating system and version
Arch Linux x86_64 - Linux 6.19.14-arch1-1
Machine specifications
No response