laravel/framework · error · BindingResolutionException

Contextual binding attribute

Error message

Contextual binding attribute [{$attribute->getName()}] has no registered handler.

What it means

BindingResolutionException from resolveFromAttribute() when a PHP 8 attribute applied to an injectable parameter has neither a registered contextual-attribute handler in the container nor a resolve() method on the attribute instance itself. The container resolves such attributes either via a registered Closure or by calling $instance->resolve(); if neither exists it cannot produce a value.

Solutions

  1. Register a handler: Illuminate\Container\Context::registerAttribute(MyAttribute::class, fn (...) => $value) or set $container->contextualAttributes[MyAttribute::class].
  2. Add a public resolve() method to the attribute class returning the injected value.
  3. Ensure the service provider that registers contextual attributes is actually loaded in config/app.php.
  4. Verify the attribute FQCN used in code matches the registered key exactly (namespace/renaming).

Example fix

// before
#[StorageDisk('tmp')]
public function __construct(private $disk) {}
// no handler registered
// after
// in a service provider boot():
Context::registerAttribute(StorageDisk::class, function (StorageDisk $attr, Container $c) {
    return Storage::disk($attr->disk);
});
Defensive patterns

Strategy: validation

Validate before calling

// Ensure every attribute used in injection has a handler.
use Illuminate\Container\Context;

$attrClass = MyAttribute::class;
if (! isset(app()->contextualAttributes[$attrClass]) && ! method_exists($attrClass, 'resolve')) {
    Context::registerAttribute($attrClass, function (\ReflectionAttribute $a, $container, $parameter) {
        return /* resolved value */;
    });
}

Type guard

function attributeHasHandler(string $attributeClass, \Illuminate\Container\Container $c): bool
{
    return isset($c->contextualAttributes[$attributeClass])
        || method_exists($attributeClass, 'resolve');
}

Try / catch

use Illuminate\Contracts\Container\BindingResolutionException;

try {
    $instance = app()->make(UsesAttributes::class);
} catch (BindingResolutionException $e) {
    if (str_contains($e->getMessage(), 'Contextual binding attribute')) {
        // register the attribute handler in a provider, then retry
    }
    throw $e;
}

Prevention

When it happens

Trigger: Using a custom #[MyAttribute] attribute on a constructor parameter but never registering it via Context::registerAttribute() / $container->contextualAttributes[]; using a built-in attribute whose handler registration was skipped; attribute class implemented without a resolve() method.

Common situations: Migrating to PHP 8 attribute-based injection without wiring the handler; package providing the attribute but its service provider not loaded; renaming the attribute class so the registered FQCN no longer matches.

Related errors


AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11). Data as JSON: /api/errors/8bfd3e6c32d1c482. Report an issue: GitHub.

Appendix: source

Thrown at src/Illuminate/Container/Container.php:1412

    /**
     * Resolve a dependency based on an attribute.
     *
     * @return mixed
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function resolveFromAttribute(ReflectionAttribute $attribute, ReflectionParameter $parameter)
    {
        $handler = $this->contextualAttributes[$attribute->getName()] ?? null;

        $instance = $attribute->newInstance();

        if (is_null($handler) && method_exists($instance, 'resolve')) {
            $handler = $instance->resolve(...);
        }

        if (is_null($handler)) {
            throw new BindingResolutionException("Contextual binding attribute [{$attribute->getName()}] has no registered handler.");
        }

        return $handler($instance, $this, $parameter);
    }

    /**
     * Throw an exception that the concrete is not instantiable.
     *
     * @param  string  $concrete
     * @return void
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    protected function notInstantiable($concrete)
    {
        if (! empty($this->buildStack)) {
            $previous = implode(', ', $this->buildStack);

View on GitHub (pinned to e0f6eb3518)