laravel/framework · error · InvalidArgumentException

Unable to find observer

Error message

Unable to find observer: {$class}

What it means

Thrown by resolveObserverClassName() when the value passed to an observer registration (e.g. Model::observe($class)) is a string that does not correspond to an existing class. The method resolves objects to their class, accepts existing class strings, and rejects anything class_exists() cannot find.

Solutions

  1. Create the observer class at the given FQCN with the correct namespace and filename.
  2. Verify the namespace and class name match exactly; run composer dump-autoload.
  3. Pass the observer class constant (UserObserver::class) instead of a string to avoid typos.
  4. Confirm the observer is registered in AppServiceProvider (or a dedicated provider) only after the class exists.

Example fix

// before
User::observe('App\Observers\UserObserver'); // class does not exist

// after
// 1) create app/Observers/UserObserver.php with namespace App\Observers;
User::observe(App\Observers\UserObserver::class);
Defensive patterns

Strategy: validation

Validate before calling

$observerClass = App\Observers\UserObserver::class;
if (! class_exists($observerClass)) {
    throw new \LogicException("Observer {$observerClass} does not exist; run composer dump-autoload or create the class.");
}
User::observe($observerClass);

Type guard

function observerClassExists(string $class): bool
{
    return class_exists($class);
}

Prevention

When it happens

Trigger: Calling User::observe('App\Observers\UserObserver') where App\Observers\UserObserver does not exist (not defined, wrong namespace, or not autoloaded). Also passing a misspelled or fully-qualified-but-wrong class string.

Common situations: Registering observers in a service provider with a class string that was renamed or never created; the observer file exists but the namespace/filename mismatch prevents autoloading; copy-pasting an observe() call from another model without adjusting the class; missing composer dump-autoload after adding the file.

Related errors


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

Appendix: source

Thrown at src/Illuminate/Database/Eloquent/Concerns/HasEvents.php:123

    /**
     * Resolve the observer's class name from an object or string.
     *
     * @param  object|string  $class
     * @return class-string
     *
     * @throws \InvalidArgumentException
     */
    private function resolveObserverClassName($class)
    {
        if (is_object($class)) {
            return get_class($class);
        }

        if (class_exists($class)) {
            return $class;
        }

        throw new InvalidArgumentException('Unable to find observer: '.$class);
    }

    /**
     * Get the observable event names.
     *
     * @return string[]
     */
    public function getObservableEvents()
    {
        return array_merge(
            [
                'retrieved', 'creating', 'created', 'updating', 'updated',
                'saving', 'saved', 'restoring', 'restored', 'replicating',
                'trashed', 'deleting', 'deleted', 'forceDeleting', 'forceDeleted',
            ],
            $this->observables
        );
    }

View on GitHub (pinned to e0f6eb3518)