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.

UniValueType(), 
    });
    if (request.params[0].get_array().size() != 1) {
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Array must contain exactly one raw transaction for now");
    }
    CMutableTransaction mtx;
    if (!DecodeHexTx(mtx, request.params[0].get_array()[0].get_str())) {
        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
    }
    CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
    const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ?
                                             DEFAULT_MAX_RAW_TX_FEE_RATE :
                                             CFeeRate(AmountFromValue(request.params[1]));
    CTxMemPool& mempool = EnsureMemPool(request.context);
    int64_t virtual_size = GetVirtualTransactionSize(*tx);
    CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
    UniValue result(UniValue::VARR);
    UniValue result_0(UniValue::VOBJ);
    result_0.pushKV("txid", tx->GetHash().GetHex());
    result_0.pushKV("wtxid", tx->GetWitnessHash().GetHex());
    TxValidationState state;
    bool test_accept_res;
    CAmount fee{0};
    {
        LOCK(cs_main);
        test_accept_res = AcceptToMemoryPool(mempool, state, std::move(tx),
            nullptr , false ,  true, &fee);
    }
    
    if (test_accept_res && max_raw_tx_fee && fee > max_raw_tx_fee) {