HTTP request error. RejectionCode: SysTransient, Error: Canister http responses were different across replicas, and no consensus was reached

My HTTP outcalls work fine when I develop locally but I’ve got following error when deployed on mainnet:

HTTP request error. RejectionCode: SysTransient, Error: Canister http responses were different across replicas, and no consensus was reached

Why then and how to overcome the issue?

It’s maybe because I query OpenAI and each replica gets a different answers given the generative nature of the answer? If that’s correct, does it mean OpenAI cannot be queried from a canister on the IC?

Yep. At least for chat, you could try using https://platform.openai.com/docs/api-reference/chat/create#chat-create-seed

Edit: Or since you are using a proxy anyway you could add an idempotency key and only make the actual request from the proxy once.

1 Like

Damn, that was overengineered. I think it took me close to five hours to make it happen.

Indeed, the solution was to extend my proxy to support an idempotency key in order to always return the same successful result for the same key. The tricky part was that within the proxy, the request had to be made atomic, given that the functions can run in parallel at the same time and also because OpenAI crashes with an error if too many requests are sent. So, I had to put requests in a database in an atomic way, and for those requests that were already queued, implement a try/repeat/timeout mechanism to wait until the first request was over.

In addition, I also needed to adjust the smart contract to transform the response in order to trim the information that is not necessary and which can be dynamic, therefore cannot be replicated. I also needed a few more minutes for this particular step because the examples in the IC documentation are outdated.

Nevertheless, it worked out. Thanks for the hint @domwoe :+1:

Screenshot from mainnet for posterity.

2 Likes

Sounds like you had a great Sunday morning :sweat_smile:

1 Like

Indeed, it started with waking up at 6:30 am for no particular reason :smiling_face_with_tear:. At least I had enough time to build the above solution.

For posterity, both use cases showcased by the demo app work out. Implementation is over; I can go have a nap.

I am also getting a similar error. But mine comes when I try making a write function call to a smart contract that’s deployed on sepolia.

This is the error

Call was rejected:
Request ID: 13ce59c70a8e2f4b03cca578736374d7b942e21e5299f96217d81abc4e102536
Reject code: 5
Reject text: Error from Canister taanb-caaaa-aaaad-aaevq-cai: Canister called `ic0.trap` with message: Error: HttpOutcallError(IcError { code: SysTransient, message: "No consensus could be reached. Replicas had different responses. Details: request_id: 7106094, timeout: 1736802971612371815, hashes: [e05b4f4ddcdc6b5318197c75c4c877d019720e4416afac1ffcef43239b22a12e: 17], [9fbe9b9b8814c8707038c834bbd380e813cf0a360aa5e67e205d57f4a583b480: 7], [892ba6b28a2fe8df8440bc7a5ad9d16ed34a180cefc81b589329596dfdda9641: 6]" }).
Consider gracefully handling failures from this canister or altering the canister to handle exceptions. See documentation: http://internetcomputer.org/docs/current/references/execution-errors#trapped-explicitly

This is how my code looks like

// rest of code 
        let result = contract_interaction(
            contract_details,
            value,
            get_rpc_services(), 
            fee_estimates.max_priority_fee_per_gas,
            key_id(),
            vec![],
            EVM_RPC,
        ).await.map_err(|(code, msg)| format!("Error {:?}: {}", code, msg))?;  
// rest of code 

This is the get_rpc_services() function that’s returning the error

fn get_rpc_services() -> RpcServices {
    RpcServices::Custom { 
        chainId: 11155111, 
        services: vec![
            RpcApi {
                url: "https://eth-sepolia.g.alchemy.com/v2/<my_api_key>".to_string(),
                headers: None,
            },
            RpcApi {
                url: "https://sepolia.infura.io/v3/<my_api_key>".to_string(),
                headers: None,
            }
        ]
    }
}

I have tried all other methods and none of them was successful

  1. Using only a single RPC service
fn get_rpc_service() -> RpcApi {
    RpcApi {
        url: "https://eth-sepolia.g.alchemy.com/v2/<my_api_key>".to_string(),
        headers: None,
    }
}

// rest of my code 

let result = contract_interaction(
            contract_details,
            value,
            RpcServices::Custom { 
                chainId: 11155111, 
                services: vec![get_rpc_service()]
            },
            fee_estimates.max_priority_fee_per_gas,
            key_id(),
            vec![],
            EVM_RPC,
        ).await.map_err(|(code, msg)| format!("Error {:?}: {}", code, msg))?;   

  1. Using multiple RPC services from the evm_rpc_canister_services package
// rest of my code 

let result = contract_interaction(
            contract_details,
            value,
            RpcServices::EthSepolia(Some(vec![
                EthSepoliaService::PublicNode,
                EthSepoliaService::BlockPi,
                EthSepoliaService::Ankr,
            ])),
            fee_estimates.max_priority_fee_per_gas,
            key_id(),
            vec![],
            EVM_RPC,
        ).await.map_err(|(code, msg)| format!("Error {:?}: {}", code, msg))?; 

// rest of my code 

All of them were returned the same error of no consensus could be reached

You might want to start your own thread since this is quite an old one, and I’ve never personally tried to reach Alchemy or Infura. Generally speaking, the known issues I’m aware of that can lead to this error are related to the non-reproducibility of the responses provided by Web2 APIs. I usually address these by implementing a transform function in the canister, adding an idempotency key for the requests, and creating a Web2 proxy in between.

1 Like