The one page checkout would always hang after Billing details tab. It would never go to Shipping tab.
- Apache error log had no errors.
- Firebug had no JS errors.
- var/log/exception.log and var/log/system.log were both empty
In Firebug, it was obvious that saveBilling() AJAX call was running as it should. However, getAdditional call, which follows saveBilling(), was acting strange. It was also returning HTTP status 200=OK, but the its response content was strange. Its response contained a list of update XML files.
After a few more thoughts, I remembered that I had modified code/core/Mage/core/Model/Layout/Update.php file. Specifically, I had modified function getFileLayoutUpdatesXml() to print out all loaded XML files, for debugging some layout update problems I had previously experienced. Obviously, I forgot about this, and it crashed my checkout process.
After commenting out this printout code, checkout instantly started working again. I decided to write about this as I think these problems occur often in practice: error logs are empty, but the application still malfunctions. This time, it was matter of wrong input data, returned by getAdditional(). This data contained no clues which Magento JS expected to move forward.