Verified issues with workarounds and prevention strategies
Double-clicking "Place Order" or concurrent API calls can create duplicate orders if the QuoteMutex is not properly used.
The placeOrder operation is not atomic. If two requests hit the same quote before either completes, both may succeed in creating orders.
// Always use QuoteMutex for order placement
$this->quoteMutex->execute(
[$cartId],
function () use ($quote) {
// Re-load quote inside mutex to check is_active
$quote = $this->quoteRepository->get($quote->getId());
if (!$quote->getIsActive()) {
throw new LocalizedException(__('Quote already converted'));
}
return $this->placeOrder($quote);
}
);
When product prices are updated in the admin, existing cart items may show outdated prices until the customer modifies their cart.
The UpdateQuoteItems plugin marks quotes for recollection. Ensure this plugin is active and run:
// Force totals recollection on cart access
$quote->setTotalsCollectedFlag(false);
$quote->collectTotals();
$this->quoteRepository->save($quote);
Masked quote IDs are generated using predictable random sources in some configurations, potentially allowing cart enumeration attacks.
Implement rate limiting on guest cart endpoints and consider additional validation layers. Magento 2.4.4+ improved masked ID generation entropy.
When adding products with complex custom options, items may incorrectly merge or fail to merge based on option comparison logic.
Implement a custom Quote\Model\Quote\Item\Option\ComparatorInterface that handles your specific option comparison needs.
REST/GraphQL APIs may not apply the same address validation as the frontend checkout, allowing invalid addresses to be saved.
Add custom validation rules to QuoteValidationComposite that explicitly validate all address fields regardless of entry method.
Shipping rates may be cached and not recalculated when the shipping address is updated, showing rates for the previous address.
// Force shipping rate recollection
$address->setCollectShippingRates(true);
$address->collectShippingRates();
$quote->collectTotals();
The quote table grows indefinitely with abandoned carts, causing database performance degradation over time.
Configure quote lifetime in admin: Stores > Configuration > Sales > Checkout > Quote Lifetime. Run the quote cleanup cron job regularly.
Coupon code comparison is case-sensitive in some areas and case-insensitive in others, leading to inconsistent behavior.
Standardize all coupon codes to uppercase in your SalesRule configuration and validate input accordingly.
Carts containing only virtual products may still require shipping address input in some checkout configurations.
Check $quote->isVirtual() before requiring shipping address in custom checkout implementations.
Wrap any quote modification that affects order placement in the QuoteMutex to prevent race conditions.
When displaying cart to customer after any change, call collectTotals() to ensure accurate pricing.
Always run the full QuoteValidationComposite before attempting order placement, especially for API integrations.
Configure quote lifetime and ensure the sales_clean_quotes cron job runs regularly.
Implement rate limiting on guest cart endpoints to prevent enumeration and abuse attacks.
Test product option comparison thoroughly for configurable, bundle, and custom option products.