{"id":"b2c045515605e7fa","repo":"laravel/framework","slug":"unable-to-bind-custom-driver-callback-b2c045","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/Cache/CacheManager.php","lineNumber":557,"sourceCode":"        $name = enum_value($name) ?? $this->getDefaultDriver();\n\n        unset($this->stores[$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":539,"sourceCodeEnd":575,"githubUrl":"https://github.com/laravel/framework/blob/bd6b5437e6ad87bb49f9b426724f07a9f64e9683/src/Illuminate/Cache/CacheManager.php#L539-L575","documentation":"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).","triggerScenarios":"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.","commonSituations":"Writing a custom cache driver registration with a static closure out of habit. Refactoring a closure to static fn () => ... which breaks rebinding.","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."],"exampleFix":"// before\nCache::extend('mydriver', static function ($app, $config) {\n    return new Repository(new MyStore());\n});\n\n// after\nCache::extend('mydriver', function ($app, $config) {\n    return new Repository(new MyStore());\n});","handlingStrategy":"validation","validationCode":"$callback = function ($app, $config) { return new \\Illuminate\\Cache\\Repository(new MyStore()); };\n$reflection = new \\ReflectionFunction($callback);\nif ($reflection->isStatic()) {\n    throw new \\LogicException('Cache::extend() requires a non-static closure.');\n}\nCache::extend('mydriver', $callback);","typeGuard":"function isBindableClosure(\\Closure $c): bool\n{\n    return ! (new \\ReflectionFunction($c))->isStatic();\n}","tryCatchPattern":"try {\n    Cache::extend('mydriver', $cb);\n} catch (\\RuntimeException $e) {\n    if ($e->getMessage() === 'Unable to bind custom driver callback') {\n        // replace static closure with a normal closure\n    }\n    throw $e;\n}","preventionTips":["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."],"tags":["cache","custom-drivers","closures","configuration"],"analyzedSha":"bd6b5437e6ad87bb49f9b426724f07a9f64e9683","analyzedAt":"2026-08-06T00:28:32.783Z","schemaVersion":2}