joinpsbts builds a new transaction from the inputs and outputs of the given PSBTs, so any existing signatures are no longer valid for it. PartiallySignedTransaction::AddInput handles that by clearing partial_sigs and the final scriptSig/witness (psbt.cpp:180), but that code predates Taproot and was never extended to the Taproot and MuSig2 fields.
So a Taproot input that was signed before the join keeps its old taproot_key_path_sig. SignTaproot (sign.cpp:608) doesn't produce a new key path signature when one is already present, so the input can't be completed afterwards:
- a bech32 (P2WPKH) input: after
joinpsbts,walletprocesspsbtre-signs and returnscomplete: true - a bech32m (P2TR) input:
taproot_key_path_sigis still there after the join, andwalletprocesspsbt/finalizepsbtreturncomplete: false.utxoupdatepsbt,descriptorprocesspsbtand signing again don't help, so the only way out is editing the PSBT by hand.
Script path signatures (taproot_script_path_sigs) behave the same. For MuSig2 the old public nonce is kept, but the secret nonce is looked up by a session id that includes the old sighash, so no new partial signature is made either.
This also clears m_tap_key_sig, m_tap_script_sigs, m_musig2_pubnonces and m_musig2_partial_sigs in the v0 branch of AddInput. Participant pubkeys are key data, not signatures, so they're kept. The v2 branch is unchanged: there, adding inputs is governed by the BIP370 modifiable flags.
The new check in rpc_psbt.py signs a v0 PSBT with a P2TR input, joins it with another one, and checks that the key path signature is gone and the joined PSBT can be signed. It fails on master and passes with the fix. wallet_musig.py still passes.