TransferHelper::transferFrom: transferFrom failed from UniswapV2Call flash swap contract

https://ethereum.stackexchange.com/questions/144985/transferhelpertransferfrom-transferfrom-failed-from-uniswapv2call-flash-swap

After days of failures and countless searches, i ask for help to understand why my flash swap contract returns the "TransferHelper::transferFrom: transferFrom failed" error, the error occurs in uniswapV2Call -> swapExactTokensForTokens -> TransferHelper.safeTransferFrom when i try to sell the borrowed tokens from Uniswap to Sushiswap. This is the contract:

// SPDX-License-Identifier: MIT
pragma solidity =0.6.6;
import "@uniswap/v2-periphery/contracts/libraries/UniswapV2Library.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Callee.sol"; 
import "@uniswap/v2-core/contracts/interfaces/IERC20.sol";
import "@uniswap/lib/contracts/libraries/TransferHelper.sol";
// flash swap contract
contract FlashSwap is IUniswapV2Callee {
    address public owner;
    constructor() public {
        owner = msg.sender;
    }
    using SafeMath for uint256;
    address private constant UniswapV2Factory = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
    address public constant SUSHISWAP_V2_ROUTER = 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506;
    IUniswapV2Router02 private sushi_router = IUniswapV2Router02(SUSHISWAP_V2_ROUTER);
    function executeTrade(address token0, address token1, uint amount0, uint amount1) public {
    
        address pairAddress = IUniswapV2Factory(UniswapV2Factory).getPair(token0, token1); 
        require(pairAddress != address(0), "Could not find pool on uniswap"); 
        bytes memory data = abi.encode(pairAddress);
        IUniswapV2Pair(pairAddress).swap(amount0, amount1, address(this), data);
    }
    function uniswapV2Call(address _sender, uint _amount0, uint _amount1, bytes calldata _data) override external {
        address[] memory pathA = new address[](2);
        address[] memory pathB = new address[](2);
        
        uint amountTokenBorrowed = _amount0 == 0 ? _amount1 : _amount0; 
 
        address token0 = IUniswapV2Pair(msg.sender).token0(); 
        address token1 = IUniswapV2Pair(msg.sender).token1(); 
        require(msg.sender == UniswapV2Library.pairFor(UniswapV2Factory, token0, token1), "Invalid Request");
        
        require(_sender == address(this), "!sender");
        require(_amount0 == 0 || _amount1 == 0);
        // create and populate path array for sushiswap swapExactTokensForTokens function.  
        pathA[0] = _amount0 == 0 ? token1 : token0; 
        pathA[1] = _amount0 == 0 ? token0 : token1; 
        // create and populate path array for uniswap getAmountsIn function.
        pathB[0] = _amount0 == 0 ? token0 : token1; 
        pathB[1] = _amount0 == 0 ? token1 : token0;
        IERC20 token = IERC20(_amount0 == 0 ? token1 : token0);
                     
        token.approve(address(sushi_router), amountTokenBorrowed);
        // calculate the amount of tokens we need to reimburse uniswap for the flashloan 
        uint amountRequired = UniswapV2Library.getAmountsIn(UniswapV2Factory, amountTokenBorrowed, pathB)[0]; 
        
        // sell borrowed tokens on sushiswap
        uint amountReceived = sushi_router.swapExactTokensForTokens(amountTokenBorrowed, amountRequired, pathA, address(this), block.timestamp + 60)[1]; 
        require(amountReceived > amountRequired, "amountReceived <= amountRequired!");
        IERC20 outputToken = IERC20(_amount0 == 0 ? token0 : token1);
        
        // amount to payback flashloan 
        // amountRequired is the amount we need to payback 
        outputToken.transfer(msg.sender, amountRequired);   
        // send profit (remaining tokens)
        outputToken.transfer(owner, amountReceived - amountRequired);  
    }
    
}

I checked with Tenderly the input values to swapExactTokensForTokens and they are correct:

{
  "amountIn": "100000000000000000000",
  "amountOutMin": "89506386512945284445",
  "path": [
    "0xTokenA_borrowed", //just hiding the real addr
    "0xTokenB_to_receive" //just hiding the real addr
  ],
  "to": "0xFlashSwap", //just hiding the real addr
  "deadline": "1676458833"
}

While getAmountsOut(inside swapExactTokensForTokens) returns 93238998313501573286 which is enough to cover the amountRequired.

I also gave several approvals(approve) before, just to be sure to cover any need, here the from -> to:

TokenA -> FlashSwap

TokenB -> FlashSwap

TokenA -> sushi router

TokenB -> sushi router

TokenA -> uni router

TokenB -> uni router

TokenA -> uni pair

TokenB -> uni pair

TokenA -> sushi pair

TokenB -> sushi pair

uni pair -> FlashSwap

sushi pair -> FlashSwap

These are the TransferHelper.safeTransferFrom(inside swapExactTokensForTokens) input values:

{
  "token": "0xTokenA_borrowed",
  "from": "Uniswap Pair", //just hiding the real addr
  "to": "Sushiswap Pair", //just hiding the real addr
  "value": "100000000000000000000"
}

Than output is "execution reverted".

What could be the problem?