How To

How to Fix Checkout Infinite Loop Detected Issue in Magento 2?

Hello Magento Friends,

In today’s blog, I will give you a solution for How to Fix Checkout Infinite Loop Detected Issue in Magento 2.

In Magento 2 when a customer adds an item to the cart, they are redirected to the checkout page. There they can select their desired payment method and enter the payment details. Once the card details are entered and they click on Place Order, it shows an infinite loop detected error as shown below.

To get rid of this error, let’s look at the solution for Checkout Infinite Loop Detected Issue in Magento 2.

Steps to Fix Checkout Infinite Loop Detected Issue in Magento 2:

Step 1: Create di.xml as given below path

app\code\Vendor\Extension\etc\di.xml

Now, add the below code

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
    <preference for="Magento\Checkout\Model\Session" type="Vendor\Extension\Preference\Checkout\Model\Session" />
</config>

Step 2: Create Session.php at given below path

app\code\Vendor\Extension\Preference\Checkout\Model\Session.php

And add the below code

<?php
namespace Vendor\Extension\Preference\Checkout\Model;

use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Quote\Api\Data\CartInterface;
use Magento\Quote\Model\Quote;
use Magento\Quote\Model\QuoteIdMaskFactory;
use Psr\Log\LoggerInterface;

class Session extends \Magento\Checkout\Model\Session
{
    const CHECKOUT_STATE_BEGIN = 'begin';
    
    protected $_quote;
    protected $_customer;
    protected $_loadInactive = false;
    protected $_order;
    protected $_orderFactory;
    protected $_customerSession;
    protected $quoteRepository;
    protected $_remoteAddress;
    protected $_eventManager;
    protected $_storeManager;
    protected $customerRepository;
    protected $quoteIdMaskFactory;
    protected $isQuoteMasked;
    protected $quoteFactory;
    
    private $isLoading = false;
    private $logger;
    
    public function __construct(
        \Magento\Framework\App\Request\Http $request,
        \Magento\Framework\Session\SidResolverInterface $sidResolver,
        \Magento\Framework\Session\Config\ConfigInterface $sessionConfig,
        \Magento\Framework\Session\SaveHandlerInterface $saveHandler,
        \Magento\Framework\Session\ValidatorInterface $validator,
        \Magento\Framework\Session\StorageInterface $storage,
        \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager,
        \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory,
        \Magento\Framework\App\State $appState,
        \Magento\Sales\Model\OrderFactory $orderFactory,
        \Magento\Customer\Model\Session $customerSession,
        \Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
        \Magento\Framework\HTTP\PhpEnvironment\RemoteAddress $remoteAddress,
        \Magento\Framework\Event\ManagerInterface $eventManager,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository,
        QuoteIdMaskFactory $quoteIdMaskFactory,
        \Magento\Quote\Model\QuoteFactory $quoteFactory,
        LoggerInterface $logger = null)
    {
        $this->_orderFactory = $orderFactory;
        $this->_customerSession = $customerSession;
        $this->quoteRepository = $quoteRepository;
        $this->_remoteAddress = $remoteAddress;
        $this->_eventManager = $eventManager;
        $this->_storeManager = $storeManager;
        $this->customerRepository = $customerRepository;
        $this->quoteIdMaskFactory = $quoteIdMaskFactory;
        $this->quoteFactory = $quoteFactory;
        parent::__construct(
            $request,
            $sidResolver,
            $sessionConfig,
            $saveHandler,
            $validator,
            $storage,
            $cookieManager,
            $cookieMetadataFactory,
            $appState
        );
        $this->logger = $logger ?: ObjectManager::getInstance()
            ->get(LoggerInterface::class);
    }
    
    public function setCustomerData($customer)
    {
        $this->_customer = $customer;
        return $this;
    }
    
    public function hasQuote()
    {
        return isset($this->_quote);
    }
    
    public function setLoadInactive($load = true)
    {
        $this->_loadInactive = $load;
        return $this;
    }
    
    public function getQuote()
    {
        $this->_eventManager->dispatch('custom_quote_process', ['checkout_session' => $this]);

        if ($this->_quote === null)
        {
            if ($this->isLoading)
            {
                throw new \LogicException("Infinite loop detected, review the trace for the looping path");
            }
            $this->isLoading = true;
            $quote = $this->quoteFactory->create();
            if ($this->getQuoteId())
            {
                try
                {
                    if ($this->_loadInactive)
                    {
                        $quote = $this->quoteRepository->get($this->getQuoteId());
                    }
                    else
                    {
                        $quote = $this->quoteRepository->getActive($this->getQuoteId());
                    }

                    $customerId = $this->_customer
                        ? $this->_customer->getId()
                        : $this->_customerSession->getCustomerId();

                    if ($quote->getData('customer_id') && (int)$quote->getData('customer_id') !== (int)$customerId)
                    {
                        $quote = $this->quoteFactory->create();
                        $this->setQuoteId(null);
                    }
                    
                    if ($quote->getQuoteCurrencyCode() != $this->_storeManager->getStore()->getCurrentCurrencyCode())
                    {
                        $quote->setStore($this->_storeManager->getStore());
                        $this->quoteRepository->save($quote->collectTotals());
                        $quote = $this->quoteRepository->get($this->getQuoteId());
                    }

                    if ($quote->getTotalsCollectedFlag() === false)
                    {
                        // $quote->collectTotals(); 
                        
                        /* Here, $quote->collectTotals(); generates error because of recursive call so, by commenting $quote->collectTotals(); or whole if condition it will not go in infinite and code will work properly. Actually there is no need of $quote->collectTotals(); in this file. */                    }
                }
                catch (NoSuchEntityException $e)
                {
                    $this->setQuoteId(null);
                }
            }

            if (!$this->getQuoteId())
            {
                if ($this->_customerSession->isLoggedIn() || $this->_customer)
                {
                    $quoteByCustomer = $this->getQuoteByCustomer();
                    if ($quoteByCustomer !== null)
                    {
                        $this->setQuoteId($quoteByCustomer->getId());
                        $quote = $quoteByCustomer;
                    }
                }
                else
                {
                    $quote->setIsCheckoutCart(true);
                    $quote->setCustomerIsGuest(1);
                    $this->_eventManager->dispatch('checkout_quote_init', ['quote' => $quote]);
                }
            }

            if ($this->_customer)
            {
                $quote->setCustomer($this->_customer);
            }
            elseif ($this->_customerSession->isLoggedIn())
            {
                $quote->setCustomer($this->customerRepository->getById($this->_customerSession->getCustomerId()));
            }

            $quote->setStore($this->_storeManager->getStore());
            $this->_quote = $quote;
            $this->isLoading = false;
        }

        if (!$this->isQuoteMasked() && !$this->_customerSession->isLoggedIn() && $this->getQuoteId())
        {
            $quoteId = $this->getQuoteId();
            $quoteIdMask = $this->quoteIdMaskFactory->create()->load($quoteId, 'quote_id');
            if ($quoteIdMask->getMaskedId() === null)
            {
                $quoteIdMask->setQuoteId($quoteId)->save();
            }
            $this->setIsQuoteMasked(true);
        }

        $remoteAddress = $this->_remoteAddress->getRemoteAddress();
        if ($remoteAddress)
        {
            $this->_quote->setRemoteIp($remoteAddress);
            $xForwardIp = $this->request->getServer('HTTP_X_FORWARDED_FOR');
            $this->_quote->setXForwardedFor($xForwardIp);
        }

        return $this->_quote;
    }
    
    protected function _getQuoteIdKey()
    {
        return 'quote_id_' . $this->_storeManager->getStore()->getWebsiteId();
    }
    
    public function setQuoteId($quoteId)
    {
        $this->storage->setData($this->_getQuoteIdKey(), $quoteId);
    }
    
    public function getQuoteId()
    {
        return $this->getData($this->_getQuoteIdKey());
    }
    
    public function loadCustomerQuote()
    {
        if (!$this->_customerSession->getCustomerId())
        {
            return $this;
        }

        $this->_eventManager->dispatch('load_customer_quote_before', ['checkout_session' => $this]);

        try
        {
            $customerQuote = $this->quoteRepository->getForCustomer($this->_customerSession->getCustomerId());
        } 
        catch (NoSuchEntityException $e)
        {
            $customerQuote = $this->quoteFactory->create();
        }
        $customerQuote->setStoreId($this->_storeManager->getStore()->getId());

        if ($customerQuote->getId() && $this->getQuoteId() != $customerQuote->getId())
        {
            if ($this->getQuoteId())
            {
                $quote = $this->getQuote();
                $quote->setCustomerIsGuest(0);
                $this->quoteRepository->save(
                    $customerQuote->merge($quote)->collectTotals()
                );
                $newQuote = $this->quoteRepository->get($customerQuote->getId());
                $this->quoteRepository->save(
                    $newQuote->collectTotals()
                );
                $customerQuote = $newQuote;
            }

            $this->setQuoteId($customerQuote->getId());

            if ($this->_quote)
            {
                $this->quoteRepository->delete($this->_quote);
            }
            $this->_quote = $customerQuote;
        }
        else
        {
            $this->getQuote()->getBillingAddress();
            $this->getQuote()->getShippingAddress();
            $this->getQuote()->setCustomer($this->_customerSession->getCustomerDataObject())
                ->setCustomerIsGuest(0)
                ->setTotalsCollectedFlag(false)
                ->collectTotals();
            $this->quoteRepository->save($this->getQuote());
        }
        return $this;
    }
    
    public function setStepData($step, $data, $value = null)
    {
        $steps = $this->getSteps();
        if ($value === null)
        {
            if (is_array($data))
            {
                $steps[$step] = $data;
            }
        }
        else
        {
            if (!isset($steps[$step]))
            {
                $steps[$step] = [];
            }
            if (is_string($data))
            {
                $steps[$step][$data] = $value;
            }
        }
        $this->setSteps($steps);

        return $this;
    }
    
    public function getStepData($step = null, $data = null)
    {
        $steps = $this->getSteps();
        if ($step === null)
        {
            return $steps;
        }
        if (!isset($steps[$step]))
        {
            return false;
        }
        if ($data === null)
        {
            return $steps[$step];
        }
        if (!is_string($data) || !isset($steps[$step][$data]))
        {
            return false;
        }
        return $steps[$step][$data];
    }
    
    public function clearQuote()
    {
        $this->_eventManager->dispatch('checkout_quote_destroy', ['quote' => $this->getQuote()]);
        $this->_quote = null;
        $this->setQuoteId(null);
        $this->setLastSuccessQuoteId(null);
        return $this;
    }
    
    public function clearStorage()
    {
        parent::clearStorage();
        $this->_quote = null;
        return $this;
    }
    
    public function clearHelperData()
    {
        $this->setRedirectUrl(null)->setLastOrderId(null)->setLastRealOrderId(null)->setAdditionalMessages(null);
    }
    
    public function resetCheckout()
    {
        $this->setCheckoutState(self::CHECKOUT_STATE_BEGIN);
        return $this;
    }
    
    public function replaceQuote($quote)
    {
        $this->_quote = $quote;
        $this->setQuoteId($quote->getId());
        return $this;
    }
    
    public function getLastRealOrder()
    {
        $orderId = $this->getLastRealOrderId();
        if ($this->_order !== null && $orderId == $this->_order->getIncrementId())
        {
            return $this->_order;
        }
        $this->_order = $this->_orderFactory->create();
        if ($orderId)
        {
            $this->_order->loadByIncrementId($orderId);
        }
        return $this->_order;
    }
    
    public function restoreQuote()
    {
        $order = $this->getLastRealOrder();
        if ($order->getId())
        {
            try
            {
                $quote = $this->quoteRepository->get($order->getQuoteId());
                $quote->setIsActive(1)->setReservedOrderId(null);
                $this->quoteRepository->save($quote);
                $this->replaceQuote($quote)->unsLastRealOrderId();
                $this->_eventManager->dispatch('restore_quote', ['order' => $order, 'quote' => $quote]);
                return true;
            }
            catch (NoSuchEntityException $e)
            {
                $this->logger->critical($e);
            }
        }

        return false;
    }
    
    protected function setIsQuoteMasked($isQuoteMasked)
    {
        $this->isQuoteMasked = $isQuoteMasked;
    }
    
    protected function isQuoteMasked()
    {
        return $this->isQuoteMasked;
    }
    
    private function getQuoteByCustomer(): ?CartInterface
    {
        $customerId = $this->_customer
            ? $this->_customer->getId()
            : $this->_customerSession->getCustomerId();

        try
        {
            $quote = $this->quoteRepository->getActiveForCustomer($customerId);
        }
        catch (NoSuchEntityException $e)
        {
            $quote = null;
        }

        return $quote;
    }
}

Conclusion:

This way you can resolve the Checkout Infinite Loop Detected Issue in Magento 2. If the error still exists, Hire a Dedicated Magento Developer that will help to overcome the infinite loop detected problem at checkout in Magento 2.

Share the solution to let your developer friends be free of this issue. For more such Magento solutions, stay in touch with us.

Happy Coding!

Click to rate this post!
[Total: 11 Average: 4.3]
Dhiren Vasoya

Dhiren Vasoya is a Director and Co-founder at MageComp, Passionate ?️ Certified Magento Developer?‍?. He has more than 9 years of experience in Magento Development and completed 850+ projects to solve the most important E-commerce challenges. He is fond❤️ of coding and if he is not busy developing then you can find him at the cricket ground, hitting boundaries.?

View Comments

  • Hi

    On Changes class Session extends \Magento\Framework\Session\SessionManager
    Shows Below error
    Type Error occurred when creating object: Magento\Persistent\Observer\EmulateQuoteObserver, Argument 3 passed to Magento\Persistent\Observer\EmulateQuoteObserver::__construct() must be an instance of Magento\Checkout\Model\Session,

    • The issue seems to be due to the latest Magento version; the blog was written for the older version. We will check and update the blog with latest version ASAP.

  • Hi

    Change class Session extends \Magento\Framework\Session\SessionManager

    it shows error on the frontend
    "ype Error occurred when creating object: Magento\Persistent\Observer\EmulateQuoteObserver, Argument 3 passed to Magento\Persistent\Observer\EmulateQuoteObserver::__construct() must be an instance of Magento\Checkout\Model\Session"
    Magento2.4.3

  • It creates an compilation error after we commentted.. You can check it on 235 instance. How to resolve?

Recent Posts

Generating Thumbnails with Spatie Media Library in Laravel 11: A Step-by-Step Guide

Generating image thumbnails is a common requirement in web applications, especially when handling media-heavy content.…

7 hours ago

Enhancing Web Application Security with Laravel’s Built-In Features

In today’s digital landscape, web application security is paramount. As a powerful PHP framework, Laravel…

1 day ago

Magento 2 Extensions Digest October 2024 (New Release & Updates)

October was an exciting month for MageComp! From significant updates across our Magento 2 extension…

1 day ago

Improving Error Handling and Transition Management in Remix with useRouteError and useViewTransitionState

In modern web development, seamless navigation and state management are crucial for delivering a smooth…

1 week ago

Magento Open Source 2.4.8-Beta Release Notes

Magento Open Source 2.4.8 beta version released on October  8, 2024. The latest release of…

1 week ago

How to Create Catalog Price Rule in Magento 2 Programmatically?

Hello Magento Friends, Creating catalog price rules programmatically in Magento 2 can be a valuable…

2 weeks ago