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

  1. Give the parameter a default value, or make it nullable/optional if it is truly optional.
  2. Bind the missing interface/abstract in a service provider: $this->app->bind(SomeContract::class, SomeImplementation::class).
  3. Pass the parameter explicitly in the parameters array keyed by name: Container::call([$obj, 'doStuff'], ['id' => 42]).
  4. 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

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


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)