laravel/framework · error · RuntimeException
Unable to bind custom driver callback
Error message
Unable to bind custom driver callback
What it means
Thrown by AuthManager::extend() when bindCallbackToSelf() returns null. bindCallbackToSelf calls Closure::bindTo() on anonymous closures; bindTo returns null if PHP cannot rebind the closure to the requested scope, so the manager refuses to store an unusable creator.
Source
Thrown at src/Illuminate/Auth/AuthManager.php:280
$this->userResolver = $userResolver;
return $this;
}
/**
* 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;
}
/**
* Register a custom provider creator Closure.
*
* @param string $name
* @param \Closure $callback
* @return $this
*/
public function provider($name, Closure $callback)
{View on GitHub (pinned to bd6b5437e6)
Solutions
- Pass a regular (non-static) Closure so it can be rebound to the manager.
- Avoid wrapping the callback with Closure::fromCallable on a method that carries incompatible scope.
- If you need a static closure, build the guard instance explicitly and return it instead of relying on rebinding.
Example fix
// before
Auth::extend('custom', static function ($app, $name, $config) {
// static anonymous closure - bindTo may yield null
return new CustomGuard(...);
});
// after
Auth::extend('custom', function ($app, $name, $config) {
return new CustomGuard($app, $name, $config);
}); Defensive patterns
Strategy: validation
Validate before calling
$callback = function ($app, $name, $config) { /* ... */ };
$rebound = $callback->bindTo(app('auth.manager'), app('auth.manager')::class);
if ($rebound === null) {
throw new RuntimeException('Closure cannot be rebound; use a non-static closure.');
}
Auth::extend('custom', $callback); Type guard
function isRebindableClosure(\Closure $c, object $scope): bool
{
try {
return (new \ReflectionFunction($c))->isAnonymous()
? $c->bindTo($scope, $scope::class) !== null
: true;
} catch (\ReflectionException) {
return false;
}
} Try / catch
try {
Auth::extend('custom', $callback);
} catch (\RuntimeException $e) {
// wrap with an invokable class instead
Auth::extend('custom', app(CustomGuardFactory::class));
} Prevention
- Avoid static anonymous closures as driver creators.
- Prefer invokable class instances over anonymous closures for creators.
- Unit-test custom driver registration after defining it.
When it happens
Trigger: Calling Auth::extend('driver', $callback) where $callback is an anonymous closure that cannot be rebound to the AuthManager scope (e.g., a static closure whose bindTo with a scope fails, or a closure over incompatible bound state).
Common situations: Passing a static closure or a closure built from a non-object-bound context in a way that defeats rebinding; very rare in normal usage.
Related errors
- Unable to bind custom driver callback
- Auth guard [{$name}] is not defined.
- Auth driver [{$config['driver']}] for guard [{$name}] is not
- Authentication user provider [{$driver}] is not defined.
- User must implement CanResetPassword interface.
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/37124dd4a1cc8c39.json.
Report an issue: GitHub.