laravel/framework · error · BindingResolutionException
Unable to resolve dependency
Error message
Unable to resolve dependency [{$parameter}] in class {$parameter->getDeclaringClass()->getName()} What it means
Thrown during method/constructor dependency injection when a parameter is required (not optional, no default value), is not present in the caller-supplied parameter overrides, and the container cannot resolve it. Unlike the unresolvable-primitive case, this fires from BoundMethod::addDependencyForCallParameter for method calls where a typed dependency itself cannot be built or a non-optional parameter was not supplied.
Solutions
- Give the parameter a default value, or make it nullable/optional if it is truly optional.
- Bind the missing interface/abstract in a service provider: $this->app->bind(SomeContract::class, SomeImplementation::class).
- Pass the parameter explicitly in the parameters array keyed by name: Container::call([$obj, 'doStuff'], ['id' => 42]).
- Make the parameter a resolvable concrete class that the container can autowire.
Example fix
// before
public function generate(ReportFormatter $formatter, $mode) { ... }
Container::call([$report, 'generate']);
// after
Container::call([$report, 'generate'], ['mode' => 'csv']);
// or bind the contract
$this->app->bind(ReportFormatter::class, CsvFormatter::class); Defensive patterns
Strategy: validation
Validate before calling
// Before invoking a callable through the container, check its required params.
function ensureResolvableMethodParams(\ReflectionMethod $m, array $given): void
{
foreach ($m->getParameters() as $p) {
$hasType = $p->getType() && ! $p->getType()->isBuiltin();
if (! $hasType && ! $p->isDefaultValueAvailable() && ! $p->isOptional() && ! array_key_exists($p->getName(), $given)) {
throw new \InvalidArgumentException("Required parameter [{$p->getName()}] of [" . $m->getDeclaringClass()->getName() . "::{$m->getName()}] is not resolvable.");
}
}
}
$r = new \ReflectionMethod($obj, 'doStuff');
ensureResolvableMethodParams($r, $params);
Container::call([$obj, 'doStuff'], $params); Type guard
function methodIsFullyResolvable(\ReflectionMethod $m, array $given, \Illuminate\Container\Container $c): bool
{
foreach ($m->getParameters() as $p) {
$type = $p->getType();
$isClass = $type && ! $type->isBuiltin();
if ($p->isOptional() || $p->isDefaultValueAvailable() || array_key_exists($p->getName(), $given)) continue;
if (! $isClass || ! $c->bound($type->getName())) return false;
}
return true;
} Try / catch
use Illuminate\Contracts\Container\BindingResolutionException;
try {
Container::call([$service, 'handle'], $params);
} catch (BindingResolutionException $e) {
// log which dependency failed and either bind it or pass a parameter override
throw $e;
} Prevention
- Prefer constructor injection over Container::call() with primitive params.
- Keep required scalar params out of container-resolved constructors; inject config values explicitly.
- Bind every interface a class transitively depends on, in service providers loaded in all environments.
When it happens
Trigger: Invoking Container::call([$obj, 'doStuff']) where doStuff has a required $logger parameter that is not a resolvable class and is not passed; a controller method with a required non-class parameter (e.g. int $id) invoked by the router without route binding; a dependency whose concrete class is itself unresolvable while injecting into a method.
Common situations: Adding a new required constructor/method argument and forgetting to bind it; type-hinting an interface without a service provider binding; method signature changed but caller not updated; passing positional parameters in the wrong key so $parameters lookup by name fails.
Related errors
- Contextual binding attribute
- {$id}
- Illuminate\Container\Container::bind(): Argument #2…
- Method not provided.
- No newInstance method exists for [$concrete].
AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11).
Data as JSON: /api/errors/d2548de1c2f8c9aa.
Report an issue: GitHub.
Appendix: source
Thrown at src/Illuminate/Container/BoundMethod.php:200
unset($parameters[$className]);
} elseif ($parameter->isVariadic()) {
$variadicDependencies = $container->make($className);
$pendingDependencies = array_merge($pendingDependencies, is_array($variadicDependencies)
? $variadicDependencies
: [$variadicDependencies]);
} elseif ($parameter->isDefaultValueAvailable() && ! $container->bound($className)) {
$pendingDependencies[] = $parameter->getDefaultValue();
} else {
$pendingDependencies[] = $container->make($className);
}
} elseif ($parameter->isDefaultValueAvailable()) {
$pendingDependencies[] = $parameter->getDefaultValue();
} elseif (! $parameter->isOptional() && ! array_key_exists($paramName, $parameters)) {
$message = "Unable to resolve dependency [{$parameter}] in class {$parameter->getDeclaringClass()->getName()}";
throw new BindingResolutionException($message);
}
foreach ($pendingDependencies as $dependency) {
$container->fireAfterResolvingAttributeCallbacks($parameter->getAttributes(), $dependency);
}
$dependencies = array_merge($dependencies, $pendingDependencies);
}
/**
* Determine if the given string is in Class@method syntax.
*
* @param mixed $callback
* @return bool
*/
protected static function isCallableWithAtSign($callback)
{
return is_string($callback) && str_contains($callback, '@');View on GitHub (pinned to e0f6eb3518)