diff --git a/contracts/modules/Exec.sol b/contracts/modules/Exec.sol
index dbc3a40e..679ab37d 100644
--- a/contracts/modules/Exec.sol
+++ b/contracts/modules/Exec.sol
@@ -117,6 +117,29 @@ contract Exec is BaseLogic {
         revert("e/batch/simulation-did-not-revert");
     }
 
+    /// @notice Call batch dispatch and catch the revert and parse it to EulerBatchItemResponse[]
+    /// @param items List of operations to execute
+    /// @param deferLiquidityChecks List of user accounts to defer liquidity checks for
+    /// @dev During simulation all batch items are executed, regardless of the `allowError` flag
+    function batchDispatchSimulateDecoded(EulerBatchItem[] calldata items, address[] calldata deferLiquidityChecks) external reentrantOK returns (EulerBatchItemResponse[] memory simulation) {
+        address msgSender = unpackTrailingParamMsgSender();
+        bytes memory data = abi.encodeWithSelector(Exec.batchDispatchSimulate.selector, items, deferLiquidityChecks);
+        bytes memory inputWrapped = abi.encodePacked(data, uint160(msgSender), uint160(msg.sender)); // msg.sender is the proxy address
+        (, bytes memory reason) = moduleLookup[MODULEID__EXEC].delegatecall(inputWrapped);
+
+        bytes4 errorSelector = bytes4(reason);
+        if(errorSelector != BatchDispatchSimulation.selector){
+            revertBytes(reason);
+        }
+        assembly {
+            reason := add(reason, 0x4)
+        }
+        simulation = abi.decode(
+            reason,
+            (EulerBatchItemResponse[])
+        );
+    }
+
 
     // Average liquidity tracking
 
diff --git a/test/batch.js b/test/batch.js
index c371f645..16cca55e 100644
--- a/test/batch.js
+++ b/test/batch.js
@@ -232,6 +232,26 @@ et.testSet({
     ]
 })
 
+.test({
+    desc: "new batch simulate",
+    actions: ctx => [
+        { send: 'eTokens.eTST.deposit', args: [0, et.eth(1)], },
+        { send: 'tokens.TST.configure', args: ['transfer/revert', []] }, 
+        { action: 'sendBatch', simulate: true, deferLiquidityChecks: [ctx.wallet.address], batch: [
+            { send: 'eTokens.eTST.withdraw', args: [0, et.eth(1)], },
+        ], onResult: r => {
+            et.expect(r[0].success).to.equal(false);
+            // safeTransferFrom adds additional error bytes that we need to remove
+            // first 4 bytes are the error selector
+            // second 32 bytes are the pointer for the start of error msg
+            // third 32 bytes are the length of the error msg
+            // then we have 4 bytes of again the Error(string) selector = 08c379a0
+            // size = 4 + 32 + 32 + 4 = 72 which equals 144 length slice + 2 for 0x = 146 
+            const msg = utils.defaultAbiCoder.decode(["string"], "0x" + r[0].result.slice(146))[0];
+            et.expect(msg).to.equal("revert behaviour")
+        }},
+    ]
+})
 
 
 .run();
diff --git a/test/lib/eTestLib.js b/test/lib/eTestLib.js
index 4c90ae81..7d6a8f87 100644
--- a/test/lib/eTestLib.js
+++ b/test/lib/eTestLib.js
@@ -1455,12 +1455,7 @@ class TestSet {
             let result;
 
             if (action.simulate) {
-                try {
-                    await ctx.contracts.exec.connect(from).callStatic.batchDispatchSimulate(items, action.deferLiquidityChecks || []);
-                } catch (e) {
-                    if (e.errorName !== 'BatchDispatchSimulation') throw e;
-                    result = e.errorArgs.simulation;
-                }
+                    result = await ctx.contracts.exec.connect(from).callStatic.batchDispatchSimulateDecoded(items, action.deferLiquidityChecks || []);
             } else {
                 let tx = await ctx.contracts.exec.connect(from).batchDispatch(items, action.deferLiquidityChecks || []);
                 result = await tx.wait();