laravel/framework · error · RuntimeException

Unable to bind custom driver callback

Error message

Unable to bind custom driver callback

What it means

Thrown by FilesystemManager::extend() when bindCallbackToSelf() returns null, indicating the supplied Closure could not be re-bound to the manager instance. extend() needs the closure bound so that custom driver creators receive $this context; a null result is treated as a hard failure to register the driver.

Source

Thrown at src/Illuminate/Filesystem/FilesystemManager.php:448

        $name ??= $this->getDefaultDriver();

        unset($this->disks[$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

  1. Pass a non-static Closure that does not rely on $this if you don't need it, or accept the manager as the first argument ($app, $config) instead.
  2. Avoid static closures when registering via extend().
  3. If you need $this, register the closure as a normal method or use a class with __invoke.

Example fix

// before - static closure cannot be bound, extend() returns null
Storage::extend('gcs', static fn ($app, $config) => makeGcs($config));

// after - regular closure
Storage::extend('gcs', function ($app, $config) {
    return makeGcs($config);
});
Defensive patterns

Strategy: validation

Validate before calling

// Reject static closures before registering
$ref = new \ReflectionFunction($callback);
if ($ref->isStatic()) {
    throw new \InvalidArgumentException('Cannot bind a static closure via extend()');
}
Storage::extend($driver, $callback);

Type guard

function isBindableClosure(Closure $c): bool
{
    return ! (new \ReflectionFunction($c))->isStatic();
}

Try / catch

try {
    Storage::extend($driver, $callback);
} catch (\RuntimeException $e) {
    if (str_contains($e->getMessage(), 'Unable to bind custom driver callback')) {
        // fall back to invokable class
        Storage::extend($driver, $invokableClassInstance);
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: Calling Storage::extend($driver, $callback) with a closure that uses $this but cannot be reflected/rebound - e.g. a Closure from an internal source, a static closure, or a closure whose reflection is blocked.

Common situations: Passing a static closure (static fn) that can't be bound; wrapping a closure in a way that loses its binding; PHP version-specific reflection quirks on certain Closure types.

Related errors


AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06). Data as JSON: /data/errors/5510e3c541779e16.json. Report an issue: GitHub.