{"id":"707a75d527913c2b","repo":"laravel/framework","slug":"self-class-bind-argument-2-concrete-mus","errorCode":null,"errorMessage":"{self::class}::bind(): Argument #2 ($concrete) must be of type Closure|string|null","messagePattern":"(.+?)::bind\\(\\): Argument #2 \\(\\$concrete\\) must be of type Closure\\|string\\|null","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/Illuminate/Container/Container.php","lineNumber":381,"sourceCode":"                $abstract, $concrete, $shared\n            );\n        }\n\n        $this->dropStaleInstances($abstract);\n\n        // If no concrete type was given, we will simply set the concrete type to the\n        // abstract type. After that, the concrete type to be registered as shared\n        // without being forced to state their classes in both of the parameters.\n        if (is_null($concrete)) {\n            $concrete = $abstract;\n        }\n\n        // If the factory is not a Closure, it means it is just a class name which is\n        // bound into this container to the abstract type and we will just wrap it\n        // up inside its own Closure to give us more convenience when extending.\n        if (! $concrete instanceof Closure) {\n            if (! is_string($concrete)) {\n                throw new TypeError(self::class.'::bind(): Argument #2 ($concrete) must be of type Closure|string|null');\n            }\n\n            $concrete = $this->getClosure($abstract, $concrete);\n        }\n\n        $this->bindings[$abstract] = ['concrete' => $concrete, 'shared' => $shared];\n\n        // If the abstract type was already resolved in this container we'll fire the\n        // rebound listener so that any objects which have already gotten resolved\n        // can have their copy of the object updated via the listener callbacks.\n        if ($this->resolved($abstract)) {\n            $this->rebound($abstract);\n        }\n    }\n\n    /**\n     * Get the Closure to be used when building a type.\n     *","sourceCodeStart":363,"sourceCodeEnd":399,"githubUrl":"https://github.com/laravel/framework/blob/bd6b5437e6ad87bb49f9b426724f07a9f64e9683/src/Illuminate/Container/Container.php#L363-L399","documentation":"Thrown as a TypeError by Container::bind when the $concrete argument is neither a Closure nor a string nor null (e.g. an integer, array, object instance). The bind signature accepts mixed only because the first argument can be a Closure; once it is a string the concrete must be Closure|string|null.","triggerScenarios":"Calling $container->bind('key', 42), $container->bind('key', ['a','b']), or $container->bind('key', $someObject) (object instance rather than class name string).","commonSituations":"Confusing bind() with instance() (use instance() to register an already-built object); passing a config array as concrete; dynamic value resolved to a non-string; copy-paste mistake between singleton($abstract, $concreteClass) and a real instance.","solutions":["Pass a class name string: $container->bind(PaymentContract::class, StripeGateway::class).","Pass a Closure: $container->bind('key', fn ($app) => new MyService($app['config'])).","To register a pre-built object use instance(): $container->instance('key', $object).","Verify the variable you are passing is a string class name or Closure before calling bind."],"exampleFix":"// before\n$container->bind('cache.store', new FileStore(...));\n\n// after\n$container->instance('cache.store', new FileStore(...));\n// or\n$container->bind('cache.store', fn () => new FileStore(...));","handlingStrategy":"type-guard","validationCode":"if (! ($concrete instanceof \\Closure || is_string($concrete) || is_null($concrete))) {\n    throw new \\TypeError('concrete must be Closure|string|null');\n}\n$container->bind($abstract, $concrete);","typeGuard":"function isBindConcrete(mixed $c): bool\n{\n    return $c instanceof \\Closure || is_string($c) || $c === null;\n}","tryCatchPattern":"try {\n    $container->bind($key, $concrete);\n} catch (\\TypeError $e) {\n    if (str_contains($e->getMessage(), 'must be of type Closure|string|null')) {\n        $container->instance($key, $concrete); // fallback for objects\n    } else { throw $e; }\n}","preventionTips":["Use instance() to register pre-built objects.","Add static analysis (phpstan level 6+) to catch wrong types at lint time.","Review service-provider bind calls in code review."],"tags":["container","binding","type-error","di"],"analyzedSha":"bd6b5437e6ad87bb49f9b426724f07a9f64e9683","analyzedAt":"2026-08-06T00:28:32.783Z","schemaVersion":2}