laravel/framework · error · InvalidArgumentException
Invalid scheduled callback event. Must be a string or callab
Error message
Invalid scheduled callback event. Must be a string or callable.
What it means
Thrown by CallbackEvent::__construct() (src/Illuminate/Console/Scheduling/CallbackEvent.php:55) when the callback is neither a string nor something Reflector::isCallable() accepts. The scheduler wraps user callbacks in CallbackEvent and refuses values it cannot later invoke via the container.
Source
Thrown at src/Illuminate/Console/Scheduling/CallbackEvent.php:55
*
* @var \Throwable|null
*/
protected $exception;
/**
* Create a new event instance.
*
* @param \Illuminate\Console\Scheduling\EventMutex $mutex
* @param string|callable $callback
* @param array $parameters
* @param \DateTimeZone|string|null $timezone
*
* @throws \InvalidArgumentException
*/
public function __construct(EventMutex $mutex, $callback, array $parameters = [], $timezone = null)
{
if (! is_string($callback) && ! Reflector::isCallable($callback)) {
throw new InvalidArgumentException(
'Invalid scheduled callback event. Must be a string or callable.'
);
}
$this->mutex = $mutex;
$this->callback = $callback;
$this->parameters = $parameters;
$this->timezone = $timezone;
}
/**
* Run the callback event.
*
* @param \Illuminate\Contracts\Container\Container $container
* @return mixed
*
* @throws \Throwable
*/View on GitHub (pinned to bd6b5437e6)
Solutions
- Pass a Closure: Schedule::call(fn () => doWork()).
- Pass a callable string 'Class@method' or 'Class::method' that the container can resolve.
- Pass an invokable object (instance with __invoke).
- For job dispatch use Schedule::job(SomeJob::class) rather than Schedule::call(SomeJob::class) when the class isn't invokable.
Example fix
// before $schedule->call(ReportGenerator::class)->daily(); // not invokable // after $schedule->call(fn () => app(ReportGenerator::class)->run())->daily(); // or $schedule->job(new ReportGenerator)->daily();
Defensive patterns
Strategy: type-guard
Validate before calling
use Illuminate\Support\Reflector;
if (! is_string($cb) && ! Reflector::isCallable($cb)) {
// convert to a Closure or invokable object before Schedule::call()
} Type guard
use Illuminate\Support\Reflector;
function isValidCallback($cb): bool
{
return is_string($cb) || Reflector::isCallable($cb);
} Try / catch
try {
$schedule->call($cb)->daily();
} catch (\InvalidArgumentException $e) {
$schedule->call(fn () => null)->daily(); // safe fallback
} Prevention
- Prefer Closures for Schedule::call().
- For class-based callbacks use Schedule::job() or invokable classes.
- Validate dynamic callback inputs before scheduling.
When it happens
Trigger: Schedule::call($x) where $x is an array that isn't a valid callable array, an object without __invoke, a non-existent class/method string, or a plain scalar. Schedule::job() or other API misuse that ultimately constructs a CallbackEvent with an invalid callback.
Common situations: Passing a class-name string of a non-invokable class, passing an array ['Class', 'method'] where the method doesn't exist, or accidentally passing null/false from a bad variable.
Related errors
- 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.
- The seconds [$seconds] are not evenly divisible by 60.
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/5691f6a77f66f891.json.
Report an issue: GitHub.