A blank white page or a bare 500 - Internal Server Error in SilverStripe almost always means the framework caught a fatal error and refused to leak the stack trace because the site is running in live mode. That's by design. To see what actually broke, you flip the environment type, point the logger at a file you can read, and then start narrowing down the culprit. Here's how to do all three on a shared or VPS host.
The three environment types
SilverStripe (3, 4, 5 and 6) runs in one of three modes controlled by SS_ENVIRONMENT_TYPE: dev, test, or live. In dev you get full backtraces printed to the browser and access to the dev tools without logging in as admin. In live you get the friendly (and useless-for-debugging) error page.
Never leave a public site in
devmode. Backtraces expose file paths, config values, and sometimes database credentials. Flip it to dev, read the error, flip it back.
Enabling dev mode
On modern SilverStripe (4/5/6) the environment lives in a .env file at your project root — the same directory that holds composer.json and the public/ folder. Edit it and set:
SS_ENVIRONMENT_TYPE="dev"
SS_ERROR_LOG="silverstripe.log"
Reload the page and you'll get the real error instead of the generic 500. If you're on the legacy 3.x branch, there's no .env — you set it in mysite/_config.php instead:
Director::set_environment_type("dev");
You can also force dev mode for a single request with a query string, e.g. https://example.com/?isDev=1. It'll prompt for admin credentials. Handy when you can't reach the filesystem quickly, but the .env approach is cleaner and works even when the site is too broken to authenticate.
Finding and editing .env on a hosting panel
Dotfiles are hidden by default in most file managers. In DirectAdmin (Evolution) open the File Manager, browse to your domain's document root, and enable Show hidden files (the gear/settings toggle) so .env appears. In cPanel (Jupiter) the File Manager has a Settings button in the top-right — tick Show Hidden Files (dotfiles) before you go looking.
One gotcha specific to SilverStripe 4+: the web-facing document root is usually the public/ subfolder, but the .env lives one level above it in the project root. If your panel's document root points straight at public/, you'll need to navigate up a directory to edit the environment file.
Wiring up the error log
SilverStripe 4+ uses Monolog for error handling. The quickest way to get a file you can actually tail is the SS_ERROR_LOG variable shown above — it takes a path relative to the project root:
SS_ERROR_LOG="silverstripe.log"
That writes to <project-root>/silverstripe.log. You can also give it an absolute path like /home/user/logs/ss-errors.log if you'd rather keep logs outside the webroot (recommended, so nobody can pull the file over HTTP). The PHP process user must have write access to wherever you point it, or logging silently does nothing.
If you want finer control — different log levels, multiple files — do it in YAML, e.g. app/_config/logging.yml:
---
Name: my-logging
---
SilverStripe\Core\Injector\Injector:
Psr\Log\LoggerInterface:
calls:
LogFileHandler: [ pushHandler, [ '%$LogFileHandler' ] ]
LogFileHandler:
class: Monolog\Handler\StreamHandler
constructor:
- '../silverstripe.log'
- 'error'
On legacy 3.x, logging is set up in _config.php with the old API:
SS_Log::add_writer(new SS_LogFileWriter('/home/user/logs/ss-errors.log'), SS_Log::ERR);
Where errors actually land
You've got three separate log sources, and they don't always agree:
- The SilverStripe log — wherever
SS_ERROR_LOGpoints. Application-level exceptions and warnings. - PHP's own
error_log— fatals that kill the request before SilverStripe's handler ever runs (out-of-memory, parse errors in a module, a missing extension). Under DirectAdmin these often surface in~/domains/yourdomain.com/logs/or the per-domainphp.error.log; under cPanel check~/logs/or the Metrics > Errors page, plus a strayerror_logfile dropped in the directory where the script died. - The web server log — Apache/LiteSpeed error logs, useful when the 500 is an
.htaccessormod_rewriteproblem rather than a PHP one.
Tail the SilverStripe log while reproducing the error over SSH:
tail -f silverstripe.log
If nothing lands there but the page still 500s, the failure happened before the framework booted — check PHP's error_log next.
Flush the manifest cache
SilverStripe caches a class/config/template manifest. After a composer update, adding a module, or editing YAML, a stale manifest throws 500s that have nothing to do with your actual code. Force a rebuild by appending ?flush=1 to any URL, or run a full build:
https://example.com/dev/build?flush=1
From the command line via sake (SilverStripe 4+):
vendor/bin/sake dev/build flush=1
Chicken-and-egg: a broken live site can 500 during
dev/build?flush=1because the build itself needs the manifest it can't read. Flip to dev mode first, run the build, then flip back. If flush does nothing, the cache dir may not be writable — delete it manually. It lives in the system temp dir (e.g./tmp/silverstripe-cache-*) or asilverstripe-cache/folder in your project root if one exists.
Isolating a faulty module or syntax error
Once dev mode is on, the backtrace usually names the offending file and line directly. Two patterns dominate:
Parse/syntax errors — a stray closing ?> tag, a missing semicolon, or a copy-paste mangle in a custom class or _config.php. Lint any file you touched before blaming the framework:
php -l app/_config.php
php -l app/src/MyController.php
Broken or incompatible modules — a module that doesn't support your SilverStripe or PHP version will fatal on boot. Check what's installed and what versions Composer resolved:
composer show | grep silverstripe
composer why-not silverstripe/framework 5.0
To confirm a specific module is the cause, temporarily remove it and rebuild:
composer remove vendor/suspect-module
vendor/bin/sake dev/build flush=1
If the site comes back, you've found it — pin a compatible version or drop the module. The same debugging discipline that helps with upload limit errors and other app-level gotchas applies here: change one thing, flush, retest.
Common Gotchas & Troubleshooting
- Still seeing the friendly error after setting dev mode. You edited the wrong
.env(there may be one inpublic/and one in root — the root one wins) or an opcache is serving stale bytecode. Restart PHP-FPM or clear opcache from your panel. - Log file never appears. Almost always permissions. The web user (often
www-data, or your cPanel/DA account user under suPHP/FPM) can't write to the path.chmodthe target directory to755and make sure ownership matches the PHP process. - 500 only on
dev/build?flush=1, fine otherwise. Stale manifest plus live mode. Set dev mode, run the build, revert. - White screen with zero log output anywhere. PHP hit its memory limit or max execution time before writing anything. Bump
memory_limitto256Min your panel's PHP settings and retry — SilverStripe's manifest build is memory-hungry. - Rewrite/500 with no PHP error. Look at the
.htaccessinpublic/. A directive your host disallows (e.g. aphp_valueline under FPM) throws a server-level 500. The Apache/LiteSpeed error log names the bad line. - You left dev mode on. Set
SS_ENVIRONMENT_TYPE="live"the moment you're done. Dev backtraces are an information-disclosure risk on a public host.