octobercms/october · error · SystemException

Slug must not be empty

Error message

Slug must not be empty

What it means

Dashboard::updateDashboard($owner, $field, $definition) lowercases the slug-like $field and throws SystemException('Slug must not be empty') when strlen($field) is 0 — i.e. the request tried to update a dashboard identified by an empty slug. Note the check happens after strtolower() and only catches truly empty strings: ' ' (whitespace) passes this guard and instead fails the subsequent lookup. The next step queries dashboards by code, so an empty slug means the caller never resolved which dashboard to update.

Source

Thrown at modules/dashboard/models/Dashboard.php:139

        UserPreference::forUser()->set($this->getUserPreferencesKey($owner, $field), $definition);
    }

    /**
     * resetDashboardPreference
     */
    public function resetDashboardPreference($owner, $field)
    {
        UserPreference::forUser()->reset($this->getUserPreferencesKey($owner, $field));
    }

    /**
     * updateDashboard
     */
    public function updateDashboard($owner, $field, $definition)
    {
        $field = strtolower($field);
        if (!strlen($field)) {
            throw new SystemException('Slug must not be empty');
        }

        $dashboard = self::applyOwner($owner)->where('code', $field)->first();
        if (!$dashboard) {
            throw new ApplicationException(
                __("Cannot find a dashboard with the specified slug: \":slug\".", ['slug' => $field])
            );
        }

        $dashboard->is_custom = true;
        $dashboard->definition = $definition;
        $dashboard->save();
    }

    /**
     * scopeListDashboards
     */
    public function scopeListDashboards($query, $owner)

View on GitHub (pinned to b608633a7e)

Solutions

  1. Send the target dashboard's non-empty slug/code in the request payload using the key the controller reads (check the handler's post() key names).
  2. In the create flow, generate/persist the slug first, then call updateDashboard with it.
  3. In the controller, validate the request: if (!strlen($slug = trim(post('slug', '')))) return back()->withError(...); before touching the model.
  4. Align front-end and back-end on one key name (slug vs code) to stop silent '' defaults.

Example fix

// before
$model->updateDashboard($owner, post('slug', ''), $definition);

// after
$slug = strtolower(trim((string) post('slug', '')));
if ($slug === '') {
    throw new ApplicationException('Dashboard slug is required.');
}
$model->updateDashboard($owner, $slug, $definition);
Defensive patterns

Strategy: validation

Validate before calling

$slug = strtolower(trim((string) post('slug', '')));
if ($slug === '') {
    throw new ApplicationException('Dashboard slug is required.');
}
$model->updateDashboard($owner, $slug, $definition);

Try / catch

try {
    $model->updateDashboard($owner, $slug, $definition);
} catch (SystemException $e) {
    if (str_contains($e->getMessage(), 'Slug must not be empty')) {
        return response()->json(['error' => 'Dashboard slug is required.'], 422);
    }
    throw $e;
}

Prevention

When it happens

Trigger: An AJAX/API save-dashboard request where the 'slug' parameter is missing, null-coalesced to '' (e.g. post('slug', '')); front-end saving a newly created dashboard before assigning its code; route/controller forwarding an unset route parameter into updateDashboard.

Common situations: Dashboard creation flow sends the definition before the slug is generated; JS builds the request payload with a renamed key (code vs slug) so the back-end reads an empty value; a test calling updateDashboard($owner, '', $def) directly.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21). Data as JSON: /api/errors/11bf265ebbfe4f96. Report an issue: GitHub.