laravel/framework · error · RuntimeException
Unable to bind custom driver callback
Error message
Unable to bind custom driver callback
What it means
CacheManager::extend() calls bindCallbackToSelf() to rebind the custom creator closure to the manager instance; if that returns null it throws RuntimeException. This path indicates the closure could not be bound (e.g. a static closure or a Closure that cannot be rebound to $this).
Source
Thrown at src/Illuminate/Cache/CacheManager.php:557
$name = enum_value($name) ?? $this->getDefaultDriver();
unset($this->stores[$name]);
}
/**
* Register a custom driver creator Closure.
*
* @param string $driver
* @param \Closure $callback
*
* @param-closure-this $this $callback
*
* @return $this
*/
public function extend($driver, Closure $callback)
{
try {
$callback = $this->bindCallbackToSelf($callback) ?? throw new RuntimeException('Unable to bind custom driver callback');
} catch (ReflectionException $e) {
throw new RuntimeException('Unable to bind custom driver callback', previous: $e);
}
$this->customCreators[$driver] = $callback;
return $this;
}
/**
* Set the application instance used by the manager.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return $this
*/
public function setApplication($app)
{
$this->app = $app;View on GitHub (pinned to bd6b5437e6)
Solutions
- Use a non-static closure: Cache::extend('mydriver', function ($app, $config) { ... });.
- Avoid 'static fn' syntax when registering extend callbacks; the manager must be able to bind $this.
- After changing the closure, run config:clear so the provider re-registers.
Example fix
// before
Cache::extend('mydriver', static function ($app, $config) {
return new Repository(new MyStore());
});
// after
Cache::extend('mydriver', function ($app, $config) {
return new Repository(new MyStore());
}); Defensive patterns
Strategy: validation
Validate before calling
$callback = function ($app, $config) { return new \Illuminate\Cache\Repository(new MyStore()); };
$reflection = new \ReflectionFunction($callback);
if ($reflection->isStatic()) {
throw new \LogicException('Cache::extend() requires a non-static closure.');
}
Cache::extend('mydriver', $callback); Type guard
function isBindableClosure(\Closure $c): bool
{
return ! (new \ReflectionFunction($c))->isStatic();
} Try / catch
try {
Cache::extend('mydriver', $cb);
} catch (\RuntimeException $e) {
if ($e->getMessage() === 'Unable to bind custom driver callback') {
// replace static closure with a normal closure
}
throw $e;
} Prevention
- Always pass a non-static closure literal to Cache::extend().
- Avoid Closure::fromCallable on internal functions.
- Add a lint rule flagging static closures in extend() calls.
When it happens
Trigger: Calling Cache::extend('mydriver', static function (...)) with a static closure that cannot be bound to an object instance. Passing a Closure created from an arrow function or a non-bindable context.
Common situations: Writing a custom cache driver registration with a static closure out of habit. Refactoring a closure to static fn () => ... which breaks rebinding.
Related errors
- To enable support for closure jobs, please install the illum
- Flushing locks is only supported when the lock store is sepa
- Cache store [{$name}] is not defined.
- Driver [{$config['driver']}] is not supported.
- Session store requires session manager to be available in co
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/b2c045515605e7fa.json.
Report an issue: GitHub.