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 dev mode. 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_LOG points. 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-domain php.error.log; under cPanel check ~/logs/ or the Metrics > Errors page, plus a stray error_log file dropped in the directory where the script died.
  • The web server log — Apache/LiteSpeed error logs, useful when the 500 is an .htaccess or mod_rewrite problem 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=1 because 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 a silverstripe-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 in public/ 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. chmod the target directory to 755 and 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_limit to 256M in your panel's PHP settings and retry — SilverStripe's manifest build is memory-hungry.
  • Rewrite/500 with no PHP error. Look at the .htaccess in public/. A directive your host disallows (e.g. a php_value line 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.