EST. 2026 — Notes from real server work SYSADMIN · SECURITY · AI · DIRECTADMIN Issue 01
THE SYSADMIN ALMANAC
Home / DirectAdmin / WordPress 500s, Empty debug.log — The Fatal Is in the Apache Log
DirectAdmin

WordPress 500s, Empty debug.log — The Fatal Is in the Apache Log

by Ton-Or ·8 Jul 2026·8 min read
WordPress 500s, Empty debug.log — The Fatal Is in the Apache Log

An empty log does not mean there is no error — a fatal error that happens before WordPress logging is ready will never appear in debug.log. This case is a good example of how the web server log is always the final source of truth.

I came across an organization's WordPress site with a strange problem: the home page worked, article pages worked, but every portfolio page (/portfolio-items/อะไรก็ตาม/) returned 500.

I enabled WP_DEBUG_LOG and reloaded a page that returned 500 — debug.log was empty, with no entries at all. This is where many people get sidetracked, because instinct says "empty log = no error." What actually happens is:

The empty log trap

The fatal error during theme rendering happens before WP logging is ready — so debug.log never sees it. Do not conclude that there is no error yet.

The actual fatal error is in the apache error log

On hosting that runs PHP-FPM through apache (mod_proxy_fcgi), the per-domain logs are at:

tail -50 /var/log/httpd/domains/example-site.org.error.log

I found it immediately:

[proxy_fcgi:error] AH01071: Got error 'PHP message: PHP Fatal error:
Uncaught Error: Call to undefined method Avada_Layout::add_class()
in /home/user/domains/example-site.org/public_html/wp-content/themes/my-child-theme/single-avada_portfolio.php:18'

That made it clear — the child theme had a single-avada_portfolio.php file calling a method that no longer existed.

WordPress startsportfolio pagetheme renderfatal happens hereWP logging readynever reachedlogged hereapache error logproxy_fcgi: PHP Fatal errorno entriesdebug.logemptyThe web server log is the final source of truth
The fatal error during theme rendering happens before WP logging is ready, leaving debug.log empty. Check the apache error log where proxy_fcgi recorded it.

For sites with lots of log entries, one line can systematically identify the culprit:

grep 'Fatal' /var/log/httpd/domains/example-site.org.error.log \
  | grep -oE '/wp-content/(plugins|themes)/[^/ ]+' | sort | uniq -c | sort -rn

This immediately shows which theme/plugin accounts for the bulk of the fatal errors.

Why it broke — a recurring child theme problem

I traced the history, and this is what happened: 2 years ago, the site developer copied a template file from the parent theme (Avada) into the child theme to modify it, which is standard WP practice and perfectly valid — but that copy called an internal API from that version of Avada (Avada()->layout->add_class()).

Child theme time bombCopy templatefrom old parent version→Parent updatesmethod removed→Copied filenobody updates it→fatal 500every page using the template

Over time, Avada kept updating until the current version removed that method — the parent's other templates were updated accordingly, but nobody touched the copy in the child theme. Any page using that template = an immediate fatal error.

Check the blast radius before making a fix — how many other child theme files call the defunct API:

grep -rln 'add_class\|add_style' wp-content/themes/my-child-theme/
# โชคดี: ไฟล์เดียว

The fix I chose: rename to trigger fallback

I did not patch the file method by method, because that 11KB file might call removed APIs in several other places. Fix one and hit the next, with no end in sight. The more stable approach:

cd wp-content/themes/my-child-theme
mv single-avada_portfolio.php single-avada_portfolio.php.disabled-2026-07-04

The principle: when WP's template hierarchy cannot find a file in the child theme, it falls back to the parent — newer Avada versions already handle portfolios through their own template system. The result was that portfolio pages returned 200 again and displayed all their content, just with Avada's default layout instead of the old custom one (which the site owner was fine with).

The benefit is that it is 100% reversible — to restore the custom layout, mv it back and port the code to the new API when convenient.

Enable WP_DEBUG safely on a production site

One last addition, for when I need to debug a live site with active users:

// wp-config.php — backup ไฟล์ก่อนแก้เสมอ
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);   // สำคัญ! อย่าโชว์ error ให้คนเข้าเว็บเห็น

Then always run php -l wp-config.php first — a single syntax mistake can leave the entire site blank. And remember that, as described above, a fatal error during theme loading may still never reach debug.log. The apache error log is the final source of truth.

Summary checklist

  1. 500 only on certain page types + empty debug.log = fatal error before WP logging — do not trust an empty log
  2. The truth is in /var/log/httpd/domains/<domain>.error.log — look for proxy_fcgi + PHP Fatal
  3. grep -oE '/wp-content/...' | sort | uniq -c to find the culprit
  4. A child theme with templates copied from its parent = a time bomb whenever the parent gets a major update
  5. Fix it by renaming to trigger fallback first (reversible), then decide whether to port the code

I have run into this child theme problem on several sites now. If you are taking over maintenance of a WP site from someone else, check the copied files in the child theme first. If I have missed anything in the explanation or made a typo, I will come back and correct it later.

Want us to set this up?

Get help with server setup, configuration, migration, or troubleshooting. Save time for the work that matters.

Get a quote

Hit something like this? Stuck somewhere?

Come trade notes on the LinuxThai board

→ Continue on the board

Comments 0

No comments yet — be the first