octobercms/october · error · ApplicationException
Unable to set active theme. Missing a site definition.
Error message
Unable to set active theme. Missing a site definition.
What it means
ApplicationException thrown by `Theme::setActiveTheme()` when the site lookup fails: `Site::getEditSite()` (backend context) or `Site::getPrimarySite()` (other contexts) returned null. Winter CMS stores the active theme on the site record, so without a site row the update target is unknown and the operation aborts before touching the database.
Source
Thrown at modules/cms/classes/Theme.php:237
return self::$activeThemeCache = $theme;
}
/**
* setActiveTheme sets the active theme
*
* The active theme code is stored in the database and overrides the
* configuration cms.active_theme config item.
*/
public static function setActiveTheme(string $code)
{
$theme = static::load($code);
if ($theme->isLocked()) {
throw new ApplicationException(Lang::get('cms::lang.theme.active.is_locked', ['theme' => $code]));
}
$site = App::runningInBackend() ? Site::getEditSite() : Site::getPrimarySite();
if (!$site) {
throw new ApplicationException(__("Unable to set active theme. Missing a site definition."));
}
Db::table($site->getTable())->where('id', $site->id)->update(['theme' => $code]);
Config::set('cms.active_theme', $code);
self::resetCache();
/**
* @event cms.theme.setActiveTheme
* Fires when the active theme has been changed.
*
* Example usage:
*
* Event::listen('cms.theme.setActiveTheme', function ($code) {
* \Log::info("Theme has been changed to $code");
* });
*
*/View on GitHub (pinned to b608633a7e)
Solutions
- Run the full setup/migrations: `php artisan winter:up` (or `php artisan migrate --seed`) so the primary site row exists.
- Verify with a tinker check: `Site::getPrimarySite()` should return a model, not null.
- If the site row was soft-deleted or corrupted, recreate it via the backend multi-site settings.
Example fix
# before — sites table empty, setActiveTheme() aborts $ php artisan tinker >>> Site::getPrimarySite() # null # after — create/migrate the site records $ php artisan winter:up >>> Site::getPrimarySite() # returns the primary site model
Defensive patterns
Strategy: validation
Validate before calling
use System\Models\Site; // winter multi-site
$site = app()->runningInBackend() ? Site::getEditSite() : Site::getPrimarySite();
if (!$site) {
return back()->with('error', 'No site record found. Run `php artisan winter:up` before changing the theme.');
}
Theme::setActiveTheme($code); Try / catch
try {
Theme::setActiveTheme($code);
} catch (ApplicationException $e) {
if (str_contains($e->getMessage(), 'site definition')) {
// DB not provisioned: point the operator at setup instead of failing silently
Log::critical('setActiveTheme blocked: no site record');
return redirect()->to('/backend/system/updates');
}
throw $e;
} Prevention
- Make `winter:up` (migrations + seed) a mandatory step in every deployment runbook.
- Add a post-deploy check that Site::getPrimarySite() is non-null before enabling the app.
- When copying databases between environments, verify the sites table came across.
When it happens
Trigger: Calling setActiveTheme() on an installation whose sites table is empty or missing — migrations never run, database truncated/restored without seed data, or a console command running where no primary site is defined.
Common situations: Partial deployments where `php artisan migrate` was skipped; staging databases copied without seed rows; custom installers that create config but not the primary site; multi-site plugins whose setup step was missed.
Related errors
- Values not found for the selected row.
- cms::lang.layout.not_found_name
- cms::lang.cms_object.invalid_file
- cms::lang.theme.edit.not_found
- cms::lang.theme.active.not_set
AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21).
Data as JSON: /api/errors/cf5f85cafe57d815.
Report an issue: GitHub.