I discovered a race condition in sendrawtransaction. For details: see my comment in https://github.com/bitcoin/bitcoin/commit/1d46fe3327f6645fd79b442cd72ef422418c1a50.

If you send a raw transaction which has already been broadcasted, then you don't know whether you'll receive an RPC_TRANSACTION_ALREADY_IN_CHAIN exception, since you don't know whether a new block has just been received, which includes the transaction. There are use cases where such RPC_TRANSACTION_ALREADY_IN_CHAIN occurrences do not indicate an error; however, since this type of occurrence is very rare, developers are not likely to be aware of the possibility, and silence the exception. As a result, applications can potentially experience hard-to-diagnose, very rare errors.

I think the core of the problem is that sendrawtransaction tries to combine two use cases:
A: publish a transaction on the Bitcoin network
B: re-transmit an already known transaction to peers
RPC_TRANSACTION_ALREADY_IN_CHAIN might make sense for B, but for A (which is, IMHO, the primary use case) it is confusing.

throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ") + txids[idx].get_str());
        }
    }
    CBlockIndex* pblockindex = nullptr;
    uint256 hashBlock;
    if (!request.params[1].isNull()) {
        LOCK(cs_main);
        hashBlock = ParseHashV(request.params[1], "blockhash");
        pblockindex = LookupBlockIndex(hashBlock);
        if (!pblockindex) {
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
        }
    } else {
        LOCK(cs_main);
        
        for (const auto& tx : setTxids) {
            const Coin& coin = AccessByTxid(::ChainstateActive().CoinsTip(), tx);
            if (!coin.IsSpent()) {
                pblockindex = ::ChainActive()[coin.nHeight];
                break;
            }
        }
    }
    
    if (g_txindex && !pblockindex) {
        g_txindex->BlockUntilSyncedToCurrentChain();
    }
    LOCK(cs_main);
    if (pblockindex == nullptr) {
        const CTransactionRef tx = GetTransaction( nullptr,  nullptr, *setTxids.begin(), Params().GetConsensus(), hashBlock);