“Some customers can’t check out” is one of the most stressful messages a store owner can send. It works when you test it. It works for most people. And yet the support inbox keeps filling up.
Start with evidence, not theories
Before changing anything, collect every trace the failures leave behind and line them up by timestamp.
- Payment gateway logs and declined or abandoned transactions.
- Failed and pending orders, plus their order notes.
- PHP error logs and slow-query logs from the server.
- Browser console errors, from a customer’s screenshot or a session recording tool if you have one.
Look for what the failures have in common
Intermittent bugs almost always have a pattern. Compare failures against successes: time of day, payment method, cart contents, guest versus logged-in, browser and device. A spike at 2 a.m. points at a cron job or backup. Failures only on large carts point at timeouts.
The usual suspects
- Cached pages serving an expired nonce, so the checkout form is rejected as “session expired.”
- Slow third-party calls for tax or shipping rates that push the request past PHP’s time limit.
- Race conditions, like a payment webhook arriving before the order has finished saving.
- A third-party script that throws an error and stops the checkout JavaScript from running.
- A plugin update that changed a hook the payment flow depended on.
An intermittent bug is just a consistent bug with a condition you haven’t found yet.
Reproduce it on purpose
Once you have a theory, force the condition on staging: throttle the network, clear the cache mid-session, fill the cart until the request is slow. When you can make it fail on command, the fix is usually small.
Then write an automated checkout test that covers that exact path, so the bug can’t quietly come back after the next round of updates.

