wallet, rpc: createwalletdescriptors ignores BIP44 accounts #34553

issue BenWestgate openend this issue on February 10, 2026
  1. BenWestgate commented at 8:58 pm on February 10, 2026: contributor

    Is there an existing issue for this?

    • I have searched the existing issues

    Current behaviour

    If I import a descriptor with a non-zero BIP44 account path, then run the createwalletdescriptor command for the same address type it creates the index 0 account and deactivates the one I imported. Other address types also use account 0.

    0bitcoin rpc -testnet createwallet "blank_wallet" blank=true
    1bitcoin rpc -testnet importdescriptors '[{"desc": "pkh(tprv8ZgxMBicQKsPehov3DbrnoRUPSX6DpANYfqcZX6RCaux8pMHhDPLm1NMsiJVPRLZccrsDcDo4b8182oJ9zbTQE6uvM6VznTjqCsezwb51MT/44h/1h/1h/<0;1>/*)#c63vt4ly", "active": true, "timestamp": "now"}]'
    2bitcoin rpc -testnet gethdkeys
    3bitcoin rpc -testnet createwalletdescriptor legacy
    4bitcoin rpc -testnet createwalletdescriptor bech32m
    5bitcoin rpc -testnet gethdkeys
    
     0{
     1  "name": "blank_wallet"
     2}
     3[
     4  {
     5    "success": true,
     6    "warnings": [
     7      "Range not given, using default keypool range"
     8    ]
     9  }
    10]
    11[
    12  {
    13    "xpub": "tpubD6NzVbkrYhZ4YAqhvsGTCD5axU32P9MH7ySPr38icriLyJc4KcCvwVzE3rsiXaAHBC8QtYWhiBGdc6aZRmroQShGcWygQfErbvLULfJSi8j",
    14    "has_private": true,
    15    "descriptors": [
    16      {
    17        "desc": "pkh([3f3521a6/44h/1h/1h]tpubDC96eSBUJsfwSkkQFtdwCv2sYs3BNDVpBn7RqnpP2e1BSZDzojUT9J5SyEpZXJJtmm1mGRfpyipjQ1XhzrnxUoRT17BhWGw4G6UQimL4t42/0/*)#4q2dlgt8",
    18        "active": true
    19      },
    20      {
    21        "desc": "pkh([3f3521a6/44h/1h/1h]tpubDC96eSBUJsfwSkkQFtdwCv2sYs3BNDVpBn7RqnpP2e1BSZDzojUT9J5SyEpZXJJtmm1mGRfpyipjQ1XhzrnxUoRT17BhWGw4G6UQimL4t42/1/*)#y50vzaml",
    22        "active": true
    23      }
    24    ]
    25  }
    26]
    27{
    28  "descs": [
    29    "pkh([3f3521a6/44h/1h/0h]tpubDC96eSBUJsfwQLgFycrHgLCvgxy7BM6hbp65t1Tn9ajLQhDTHmtgWQjmgdWgyZxfNY4nGJztAYK7CYh83pNvj1V72Fe2cogcd2WJFwZK9EB/0/*)#5470vsc4",
    30    "pkh([3f3521a6/44h/1h/0h]tpubDC96eSBUJsfwQLgFycrHgLCvgxy7BM6hbp65t1Tn9ajLQhDTHmtgWQjmgdWgyZxfNY4nGJztAYK7CYh83pNvj1V72Fe2cogcd2WJFwZK9EB/1/*)#9pmw39gd"
    31  ]
    32}
    33{
    34  "descs": [
    35    "tr([3f3521a6/86h/1h/0h]tpubDCW7vJKTJGE1e5WTX7mWDmafQmsEMpaVbqFkZih8uQympr8a1FZkw7paeNXkVgE28jdZd13aexRzuCzF3NfuzQNFgAqmSU9p1DDrYeRUUoE/0/*)#e7freggd",
    36    "tr([3f3521a6/86h/1h/0h]tpubDCW7vJKTJGE1e5WTX7mWDmafQmsEMpaVbqFkZih8uQympr8a1FZkw7paeNXkVgE28jdZd13aexRzuCzF3NfuzQNFgAqmSU9p1DDrYeRUUoE/1/*)#g2vzyac4"
    37  ]
    38}
    39[
    40  {
    41    "xpub": "tpubD6NzVbkrYhZ4YAqhvsGTCD5axU32P9MH7ySPr38icriLyJc4KcCvwVzE3rsiXaAHBC8QtYWhiBGdc6aZRmroQShGcWygQfErbvLULfJSi8j",
    42    "has_private": true,
    43    "descriptors": [
    44      {
    45        "desc": "pkh([3f3521a6/44h/1h/0h]tpubDC96eSBUJsfwQLgFycrHgLCvgxy7BM6hbp65t1Tn9ajLQhDTHmtgWQjmgdWgyZxfNY4nGJztAYK7CYh83pNvj1V72Fe2cogcd2WJFwZK9EB/0/*)#5470vsc4",
    46        "active": true
    47      },
    48      {
    49        "desc": "pkh([3f3521a6/44h/1h/0h]tpubDC96eSBUJsfwQLgFycrHgLCvgxy7BM6hbp65t1Tn9ajLQhDTHmtgWQjmgdWgyZxfNY4nGJztAYK7CYh83pNvj1V72Fe2cogcd2WJFwZK9EB/1/*)#9pmw39gd",
    50        "active": true
    51      },
    52      {
    53        "desc": "pkh([3f3521a6/44h/1h/1h]tpubDC96eSBUJsfwSkkQFtdwCv2sYs3BNDVpBn7RqnpP2e1BSZDzojUT9J5SyEpZXJJtmm1mGRfpyipjQ1XhzrnxUoRT17BhWGw4G6UQimL4t42/0/*)#4q2dlgt8",
    54        "active": false
    55      },
    56      {
    57        "desc": "pkh([3f3521a6/44h/1h/1h]tpubDC96eSBUJsfwSkkQFtdwCv2sYs3BNDVpBn7RqnpP2e1BSZDzojUT9J5SyEpZXJJtmm1mGRfpyipjQ1XhzrnxUoRT17BhWGw4G6UQimL4t42/1/*)#y50vzaml",
    58        "active": false
    59      },
    60      {
    61        "desc": "tr([3f3521a6/86h/1h/0h]tpubDCW7vJKTJGE1e5WTX7mWDmafQmsEMpaVbqFkZih8uQympr8a1FZkw7paeNXkVgE28jdZd13aexRzuCzF3NfuzQNFgAqmSU9p1DDrYeRUUoE/0/*)#e7freggd",
    62        "active": true
    63      },
    64      {
    65        "desc": "tr([3f3521a6/86h/1h/0h]tpubDCW7vJKTJGE1e5WTX7mWDmafQmsEMpaVbqFkZih8uQympr8a1FZkw7paeNXkVgE28jdZd13aexRzuCzF3NfuzQNFgAqmSU9p1DDrYeRUUoE/1/*)#g2vzyac4",
    66        "active": true
    67      }
    68    ]
    69  }
    70]
    

    Related to: #29129

    Expected behaviour

    Based on the createwalletdescriptor help text,

    Creates the wallet’s descriptor for the given address type. The address type must be one that the wallet does not already have a descriptor for.

    I expected:

    • an error given an address type the wallet already has a descriptor for
    • the active account to propagate to other address types
     0{
     1  "name": "blank_wallet"
     2}
     3[
     4  {
     5    "success": true,
     6    "warnings": [
     7      "Range not given, using default keypool range"
     8    ]
     9  }
    10]
    11[
    12  {
    13    "xpub": "tpubD6NzVbkrYhZ4YAqhvsGTCD5axU32P9MH7ySPr38icriLyJc4KcCvwVzE3rsiXaAHBC8QtYWhiBGdc6aZRmroQShGcWygQfErbvLULfJSi8j",
    14    "hd_account": 1,
    15    "has_private": true,
    16    "descriptors": [
    17      {
    18        "desc": "pkh([3f3521a6/44h/1h/1h]tpubDC96eSBUJsfwSkkQFtdwCv2sYs3BNDVpBn7RqnpP2e1BSZDzojUT9J5SyEpZXJJtmm1mGRfpyipjQ1XhzrnxUoRT17BhWGw4G6UQimL4t42/0/*)#4q2dlgt8",
    19        "active": true
    20      },
    21      {
    22        "desc": "pkh([3f3521a6/44h/1h/1h]tpubDC96eSBUJsfwSkkQFtdwCv2sYs3BNDVpBn7RqnpP2e1BSZDzojUT9J5SyEpZXJJtmm1mGRfpyipjQ1XhzrnxUoRT17BhWGw4G6UQimL4t42/1/*)#y50vzaml",
    23        "active": true
    24      }
    25    ]
    26  }
    27]
    28error code: -4
    29error message:
    30Descriptor already exists
    31{
    32  "descs": [
    33    "tr([3f3521a6/86h/1h/1h]tpub.../0/*)...",
    34    "tr([3f3521a6/86h/1h/1h]tpub.../1/*)..."
    35  ]
    36}
    37[
    38  {
    39    "xpub": "tpubD6NzVbkrYhZ4YAqhvsGTCD5axU32P9MH7ySPr38icriLyJc4KcCvwVzE3rsiXaAHBC8QtYWhiBGdc6aZRmroQShGcWygQfErbvLULfJSi8j",
    40    "hd_account": 1,
    41    "has_private": true,
    42    "descriptors": [
    43      {
    44        "desc": "pkh([3f3521a6/44h/1h/1h]tpubDC96eSBUJsfwSkkQFtdwCv2sYs3BNDVpBn7RqnpP2e1BSZDzojUT9J5SyEpZXJJtmm1mGRfpyipjQ1XhzrnxUoRT17BhWGw4G6UQimL4t42/0/*)#4q2dlgt8",
    45        "active": true
    46      },
    47      {
    48        "desc": "pkh([3f3521a6/44h/1h/1h]tpubDC96eSBUJsfwSkkQFtdwCv2sYs3BNDVpBn7RqnpP2e1BSZDzojUT9J5SyEpZXJJtmm1mGRfpyipjQ1XhzrnxUoRT17BhWGw4G6UQimL4t42/1/*)#y50vzaml",
    49        "active": true
    50      },
    51      {
    52        "desc": "tr([3f3521a6/86h/1h/1h]tpub.../0/*)...",
    53        "active": true
    54      },
    55      {
    56        "desc": "tr([3f3521a6/86h/1h/1h]tpub.../1/*)...",
    57        "active": true
    58      }
    59    ]
    60  }
    61]
    

    This issue could be avoided by an hd_account option for createwalletdescriptor (see unimplemented #29130 (review)):

    It could make sense to add an … hd_account option (see #29129 (comment)) for … wallets :

    0# Add descriptors from the external signer with the specified BIP44 account
    1createwalletdescriptor hd_account=1
    

    Proposed solution: createwalletdescriptor help:

    0Named Arguments:
    1internal    (boolean, optional, default=Both external and internal will be generated unless this parameter is specified) Whether to only make one descriptor that is internal (if parameter is true) or external (if parameter is false)
    2hdkey       (string, optional, default=The HD key used by all other active descriptors) The HD key that the wallet knows the private key of, listed using 'gethdkeys', to use for this descriptor's key
    3hd_account  (numeric, optional, default=The BIP44 account used by all other active descriptors) The BIP44 account, listed using 'gethdkeys', to use for this descriptor's derivation path.
    4Proposed solution:
    

    gethdkeys help:

     0Result:
     1[                                  (json array)
     2  {                                (json object)
     3    "xpub" : "str",                (string) The extended public key
     4    "hd_account": n,               (numeric, optional) The HD account used by all active descriptors if the wallet follows BIP44
     5    "has_private" : true|false,    (boolean) Whether the wallet has the private key for this xpub
     6    "xprv" : "str",                (string, optional) The extended private key if "private" is true
     7    "descriptors" : [              (json array) Array of descriptor objects that use this HD key
     8      {                            (json object)
     9        "desc" : "str",            (string) Descriptor string representation
    10        "active" : true|false      (boolean) Whether this descriptor is currently used to generate new addresses
    11      },
    12      ...
    13    ]
    14  },
    15  ...
    16]
    

    The following behavior may also be expected for non-0 BIP44 accounts:

    Software should prevent a creation of an account if a previous account does not have a transaction history (meaning none of its addresses have been used before).

    Software needs to discover all used accounts after importing the seed from an external source. Such an algorithm is described in “Account discovery” chapter.

    However this is problematic for external signers so it should warn rather than prevent if it cannot scan the chain.

    Steps to reproduce

    0bitcoin rpc -testnet createwallet "blank_wallet" blank=true
    1bitcoin rpc -testnet importdescriptors '[{"desc": "pkh(tprv8ZgxMBicQKsPehov3DbrnoRUPSX6DpANYfqcZX6RCaux8pMHhDPLm1NMsiJVPRLZccrsDcDo4b8182oJ9zbTQE6uvM6VznTjqCsezwb51MT/44h/1h/1h/<0;1>/*)#c63vt4ly", "active": true, "timestamp": "now"}]'
    2bitcoin rpc -testnet gethdkeys
    3bitcoin rpc -testnet createwalletdescriptor legacy
    4bitcoin rpc -testnet createwalletdescriptor bech32m
    5bitcoin rpc -testnet gethdkeys
    

    Relevant log output

    No response

    How did you obtain Bitcoin Core

    Pre-built binaries

    What version of Bitcoin Core are you using?

    v30.2.0

    Operating system and version

    Debian 13

    Machine specifications

    No response

  2. achow101 commented at 9:19 pm on February 10, 2026: member

    This is the intended and expected behavior.

    createwalletdescriptor uses only the keys that are known to the wallet, it does not know about nor account for any derivation information attached to those keys.

    I also expected an hd_account option for createwalletdescriptor (see #29130 (review)):

    That was not implemented, and is not stated in the help text. There is no reason to expect that.

    createwalletdescriptor help:

    0Named Arguments:
    1internal    (boolean, optional, default=Both external and internal will be generated unless this parameter is specified) Whether to only make one descriptor that is internal (if parameter is true) or external (if parameter is false)
    2hdkey       (string, optional, default=The HD key used by all other active descriptors) The HD key that the wallet knows the private key of, listed using 'gethdkeys', to use for this descriptor's key
    3hd_account  (numeric, optional, default=The BIP44 account used by all other active descriptors) The BIP44 account, listed using 'gethdkeys', to use for this descriptor's derivation path.
    

    I don’t know where you got that from, but that is not what the help says.


    The help text should be corrected to remove the sentence “The address type must be one that the wallet does not already have a descriptor for.”. The intention is for createwalletdescriptor to be able to rotate keys in the future, so this sentence is no longer correct.

  3. willcl-ark added the label Wallet on Feb 10, 2026
  4. BenWestgate commented at 4:33 am on February 11, 2026: contributor

    createwalletdescriptor uses only the keys that are known to the wallet, it does not know about nor account for any derivation information attached to those keys.

    It should know about account to use it by default, otherwise it makes descriptors with different active accounts per address type for one HD key which is unexpected.

    I also expected an hd_account option for createwalletdescriptor…

    That was not implemented, and is not stated in the help text.

    Then consider this issue a feature request for a “createwalletdescriptor hd_account option”.

    I don’t know where you got that from, but that is not what the help says.

    I wrote it as a mock up for a potential solution which adds an hd_account option.


    The help text should be corrected to remove the sentence “The address type must be one that the wallet does not already have a descriptor for.”. The intention is for createwalletdescriptor to be able to rotate keys in the future, so this sentence is no longer correct.

    Is the correct sentence:

    “The address type must be one that the HD key does not already have a descriptor for.”?

    Let’s fix the help text to close this issue and move hd_account to a feature request.

    I think createwalletdescriptors should support creating/rotating accounts, and default to the first unimported account index per address type per HD key.

    This helps restore privacy if [deadbeef/purpose’/0’/0’] xpubs were compromised by rotating to [deadbeef/purpose’/0’/1’] and allows managing segregated funds with one HD key.


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-02-11 18:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me