laravel/framework · warning · Exception
Scheduled command [{$event->command}] failed with exit code
Error message
Scheduled command [{$event->command}] failed with exit code [{$event->exitCode}]. What it means
Thrown by ScheduleRunCommand::runEvent() (src/Illuminate/Console/Scheduling/ScheduleRunCommand.php:215) when a foreground scheduled command exits with a non-zero code. It is caught internally, reported via the exception handler, and surfaces as a failed task line in the schedule:run output; background events do not raise it.
Source
Thrown at src/Illuminate/Console/Scheduling/ScheduleRunCommand.php:215
);
$this->components->task($description, function () use ($event) {
$this->dispatcher->dispatch(new ScheduledTaskStarting($event));
$start = microtime(true);
try {
$event->run($this->laravel);
$this->dispatcher->dispatch(new ScheduledTaskFinished(
$event,
round(microtime(true) - $start, 2)
));
$this->eventsRan = true;
if ($event->exitCode != 0 && ! $event->runInBackground) {
throw new Exception("Scheduled command [{$event->command}] failed with exit code [{$event->exitCode}].");
}
} catch (Throwable $e) {
$this->dispatcher->dispatch(new ScheduledTaskFailed($event, $e));
$this->handler->report($e);
}
return $event->exitCode == 0;
});
if (! $event instanceof CallbackEvent) {
$this->components->bulletList([
$event->getSummaryForDisplay(),
]);
}
}
/**View on GitHub (pinned to bd6b5437e6)
Solutions
- Run the command manually with php artisan <name> to reproduce and read the actual exception.
- Make the command robust: catch expected exceptions and return SUCCESS or a controlled FAILURE.
- Add monitoring/logging inside the command; check storage/logs and the failed_jobs table.
- If the failure is acceptable, run the event in the background to suppress this throw, or wrap with ->onFailure(...)/->emailOutputOnFailure(...).
Example fix
// before
// command body throws -> exit code 1
$schedule->command('reports:send')->daily();
// after
// in the command handle():
try { $this->send(); return self::SUCCESS; }
catch (\Throwable $e) { $this->error($e->getMessage()); return self::FAILURE; }
// and/or
$schedule->command('reports:send')->daily()->onFailure(fn () => logger('reports failed')); Defensive patterns
Strategy: try-catch
Validate before calling
$exit = \Illuminate\Support\Facades\Artisan::call('reports:send');
if ($exit !== 0) {
// don't schedule a known-failing command; fix it first
} Type guard
function commandSucceeds(string $name): bool
{
return \Illuminate\Support\Facades\Artisan::call($name) === 0;
} Try / catch
// handled inside ScheduleRunCommand; in your command handle():
try {
$this->send();
return self::SUCCESS;
} catch (\Throwable $e) {
$this->error($e->getMessage());
return self::FAILURE;
} Prevention
- Test scheduled commands locally before deploying.
- Add ->onFailure() / ->emailOutputOnFailure() hooks for visibility.
- Make commands idempotent and resilient to transient failures.
- Monitor schedule:run output and storage/logs.
When it happens
Trigger: A scheduled Artisan command (Event, not CallbackEvent) returns non-zero exitCode (e.g. command throws, fails an assertion, or returns self::FAILURE). Triggered when schedule:run / schedule:work executes the due event.
Common situations: Scheduled maintenance/cleanup commands that error on bad input, missing dependencies, expired credentials, or DB connectivity. Often intermittent (network/API flakiness).
Related errors
- Invalid scheduled callback event. Must be a string or callab
- Scheduled closures can not be run in the background.
- A scheduled event name is required to prevent overlapping. U
- A scheduled event name is required to only run on one server
- The seconds [$seconds] must be greater than zero.
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/53a63fcf167f40da.json.
Report an issue: GitHub.