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.
Solutions
- 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).
- In the create flow, generate/persist the slug first, then call updateDashboard with it.
- In the controller, validate the request: if (!strlen($slug = trim(post('slug', '')))) return back()->withError(...); before touching the model.
- 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
- Trim and validate the slug in the controller before calling updateDashboard.
- Generate and persist the dashboard slug before allowing definition saves from the UI.
- Keep the request payload key name (slug) in sync between front-end and back-end.
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 argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Cannot find a dashboard with the specified slug: ":slug".
- Custom widget class [ ] is not set.
- Custom widget class [ ] is not set.
- The property name is not specified.
- Attribute name cannot be empty for
AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21).
Data as JSON: /api/errors/11bf265ebbfe4f96.
Report an issue: GitHub.
Appendix: 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)