{"id":"5510e3c541779e16","repo":"laravel/framework","slug":"unable-to-bind-custom-driver-callback-5510e3","errorCode":null,"errorMessage":"Unable to bind custom driver callback","messagePattern":"Unable to bind custom driver callback","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/Illuminate/Filesystem/FilesystemManager.php","lineNumber":448,"sourceCode":"        $name ??= $this->getDefaultDriver();\n\n        unset($this->disks[$name]);\n    }\n\n    /**\n     * Register a custom driver creator Closure.\n     *\n     * @param  string  $driver\n     * @param  \\Closure  $callback\n     *\n     * @param-closure-this  $this  $callback\n     *\n     * @return $this\n     */\n    public function extend($driver, Closure $callback)\n    {\n        try {\n            $callback = $this->bindCallbackToSelf($callback) ?? throw new RuntimeException('Unable to bind custom driver callback');\n        } catch (ReflectionException $e) {\n            throw new RuntimeException('Unable to bind custom driver callback', previous: $e);\n        }\n\n        $this->customCreators[$driver] = $callback;\n\n        return $this;\n    }\n\n    /**\n     * Set the application instance used by the manager.\n     *\n     * @param  \\Illuminate\\Contracts\\Foundation\\Application  $app\n     * @return $this\n     */\n    public function setApplication($app)\n    {\n        $this->app = $app;","sourceCodeStart":430,"sourceCodeEnd":466,"githubUrl":"https://github.com/laravel/framework/blob/bd6b5437e6ad87bb49f9b426724f07a9f64e9683/src/Illuminate/Filesystem/FilesystemManager.php#L430-L466","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Avoid static closures when registering via extend().","If you need $this, register the closure as a normal method or use a class with __invoke."],"exampleFix":"// before - static closure cannot be bound, extend() returns null\nStorage::extend('gcs', static fn ($app, $config) => makeGcs($config));\n\n// after - regular closure\nStorage::extend('gcs', function ($app, $config) {\n    return makeGcs($config);\n});","handlingStrategy":"validation","validationCode":"// Reject static closures before registering\n$ref = new \\ReflectionFunction($callback);\nif ($ref->isStatic()) {\n    throw new \\InvalidArgumentException('Cannot bind a static closure via extend()');\n}\nStorage::extend($driver, $callback);","typeGuard":"function isBindableClosure(Closure $c): bool\n{\n    return ! (new \\ReflectionFunction($c))->isStatic();\n}","tryCatchPattern":"try {\n    Storage::extend($driver, $callback);\n} catch (\\RuntimeException $e) {\n    if (str_contains($e->getMessage(), 'Unable to bind custom driver callback')) {\n        // fall back to invokable class\n        Storage::extend($driver, $invokableClassInstance);\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Avoid static closures when calling extend().","Use a regular closure or an invokable class instead.","Let the closure accept ($app, $config) rather than relying on $this."],"tags":["filesystem","custom-driver","closure","extend","binding"],"analyzedSha":"bd6b5437e6ad87bb49f9b426724f07a9f64e9683","analyzedAt":"2026-08-06T00:28:32.783Z","schemaVersion":2}