The update finished, you reloaded the storefront, and the browser shows nothing. No error, no layout, no OpenCart. It feels like the site is gone. It is not: PHP stopped in the middle of building the page, and the reason it stopped was written down — just not on the screen in front of you.
This is the routine we run on a call-out, in order. It takes minutes rather than hours, and it works the same way on OpenCart 3.0.x and 4.x.
A white screen is a 500 you cannot see
Start with the status code, because it splits the problem in two. Ask for the storefront and the admin separately — if one of them answers, you have already halved the search space.
curl -s -o /dev/null -D - "https://example.com/" | head -n 1
curl -s -o /dev/null -D - "https://example.com/index.php?route=common/home" | head -n 1
curl -s -o /dev/null -D - "https://example.com/yonetim/index.php" | head -n 1HTTP 500 means PHP died and the web server knows about it, so the reason is in the FPM and web-server logs. HTTP 200 with an empty body is the more confusing case: PHP ran, produced nothing, and error output is switched off. That is almost always a fatal error with display_errors disabled — which is the correct production setting, and exactly why the next steps exist.
While you are here, rule out the two things that are not PHP at all. A CDN or full-page cache can keep serving the empty response long after the site itself is fixed, and a browser will happily cache it too. curl bypasses both: if curl returns HTML and your browser still shows white, the problem sits in front of OpenCart rather than inside it.
Three logs, in this order
OpenCart writes its own log to system/storage/logs/error.log, or wherever DIR_LOGS points in config.php if the storage directory has been moved out of the web root. That file is the first stop but not the whole story: OpenCart's handler only catches what PHP hands it after the framework has started. A parse error, or a crash during bootstrap, never reaches it and appears only in the PHP or web-server log.
tail -n 100 /var/www/store/system/storage/logs/error.log
tail -n 100 /var/log/php8.1-fpm.log
tail -n 200 /var/log/nginx/error.log # Apache: /var/log/apache2/error.logTurning the errors back on, for ten minutes
OpenCart's error handling lives in System, Settings, edit store, Server tab: Display Errors, Log Errors and Error Log Filename. Those three map to config_error_display, config_error_log and config_error_filename in oc_setting. If the admin is white too you cannot get there, so set them in SQL — or make PHP speak directly in the entry file.
UPDATE oc_setting SET `value` = '1'
WHERE `code` = 'config' AND `key` IN ('config_error_display','config_error_log') AND store_id = 0;<?php
// index.php — temporary, first lines only
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);Reading the line you found
An OpenCart log entry has a fixed shape: timestamp, severity, message, then the file and the line.
2026-08-04 23:14:07 - PHP Fatal error: Uncaught TypeError: count(): Argument #1
($value) must be of type Countable|array, null given in
/var/www/store/extension/acme_shipping/catalog/model/shipping/acme.php:118
Stack trace:
#0 /var/www/store/system/engine/loader.php(122): Acme\Shipping->getQuote(Array)Three habits make this quick. Read the first fatal after the deployment timestamp rather than the newest line in the file, because the later entries are usually consequences of the first. Look at the path before the line number: anything under extension/, or under catalog/controller/extension in 3.0.x, is third-party code and therefore something you can switch off. And ignore Notice and Deprecated entries while you are hunting — they are noise on almost every store and they were there yesterday too.
The five causes behind most post-update white screens
- 1The PHP version moved with the update. OpenCart 4 requires PHP 8, while a 3.0.x store and its extensions were written for PHP 7. Functions removed in PHP 8.0 — each(), create_function(), curly-brace string offsets — become fatal errors in old extension code.
- 2A stale modification cache, in 3.0.x only. system/storage/modification holds patched copies of core files; once new core files are installed, those copies no longer match. Clear the folder, then refresh from Extensions, Modifications.
- 3Template and data cache. system/storage/cache can still be serving compiled templates from the previous version.
- 4Memory. A bigger catalog or one new extension pushes past memory_limit and PHP stops mid-page, usually with no output at all.
- 5A missing PHP module or wrong ownership after restoring an archive: Call to undefined function curl_init(), or failed to open stream: Permission denied.
cd /var/www/store
rm -rf system/storage/cache/*
rm -rf system/storage/modification/* # OpenCart 3.0.x only
php -r 'foreach (["curl","gd","zip","mbstring","openssl"] as $e) printf("%-10s %s\n", $e, extension_loaded($e) ? "ok" : "MISSING");'
chown -R www-data:www-data . && find . -type d -exec chmod 755 {} \; && find . -type f -exec chmod 644 {} \;Two traps in that block. php -v and php -r report the command-line PHP, which is often neither the version nor the module set nginx uses — check the pool with php-fpm8.1 -v and the socket named in your vhost. And in 3.0.x, emptying system/storage/modification without pressing Refresh leaves your OCMOD customizations simply not applied: the store loads perfectly, and features quietly disappear.
- OpenCart 3.0.3.x
- PHP 7.4
- OpenCart 4.0.x
- PHP 8.0+
- First log to open
- system/storage/logs/error.log
Getting back online, then finding the cause
If the store is taking orders, restore first and investigate afterwards. Recovery and diagnosis are two different jobs and they do not have to happen in the same hour.
- 1Restore the pre-update file archive and database dump, then confirm that both the storefront and the admin answer 200.
- 2Copy that restored state to a staging URL and repeat the update there with display errors on.
- 3If the fatal points at an extension, disable it in the copy and repeat — one extension at a time. The log names the file, so the search space is small.
- 4Fix it on the copy, then deploy again in a quiet hour with maintenance mode on and the log open.
The routine that removes the surprise
- A staging copy of the real store, not a demo: same extensions, same theme, same PHP version.
- A database dump and a file archive taken immediately before the update — and tested by restoring them once.
- An empty error.log at the start, so that everything in it afterwards belongs to this update.
- A written extension inventory: name, version, author, last update date.
- Maintenance mode during the switch, and a curl check of both storefront and admin before it comes off.
mysqldump --single-transaction --routines opencart | gzip > /backup/oc-$(date +%F-%H%M).sql.gz
tar czf /backup/oc-files-$(date +%F-%H%M).tar.gz -C /var/www store
: > /var/www/store/system/storage/logs/error.logWhen to write to us
If the log line makes no sense, or it points at a file nobody on your team wrote, send us the last hundred lines of error.log with your OpenCart and PHP versions. During the launch campaign work is billed hourly at $10 per hour plus VAT, and you approve the estimate before anything starts. First response is within two hours, Monday to Saturday, 09:00–22:00 (GMT+3). If the store is down right now, say so in the first line.
CI/CD, SRE and GitOps; SLO/SLI and production incident command.