laravel/framework · error · InvalidArgumentException
Unable to find observer: {$class}
Error message
Unable to find observer: {$class} What it means
When registering an observer via Model::observe($class), resolveObserverClassName() requires the supplied string (or object's class) to actually exist. A non-existent class string is rejected up-front because binding event listeners against it would silently no-op.
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 bd6b5437e6)
Solutions
- Verify the FQN matches the file location (PSR-4) and the class exists.
- Run composer dump-autoload to refresh the classmap.
- Pass the ::class constant (Post::observe(AuditObserver::class)) instead of a literal string to catch typos at IDE/static-analysis time.
Example fix
// before
Post::observe('App\Observer\PostObserver'); // wrong namespace 'Observer' vs 'Observers'
// after
Post::observe(\App\Observers\PostObserver::class); Defensive patterns
Strategy: validation
Validate before calling
if (! class_exists($observerClass)) {
throw new \InvalidArgumentException("Observer class not found: {$observerClass}");
}
Post::observe($observerClass); Type guard
function observerClassExists(string $class): bool
{
return class_exists($class);
} Try / catch
try {
Post::observe(\App\Observers\PostObserver::class);
} catch (\InvalidArgumentException $e) {
if (str_contains($e->getMessage(), 'Unable to find observer')) {
\Illuminate\Support\Facades\Artisan::call('optimize:clear');
report('Observer class missing; cleared autoload cache');
}
throw $e;
} Prevention
- Pass Observer::class constants instead of string literals.
- Place observers in the PSR-4 path declared in composer.json.
- Run composer dump-autoload after creating or moving observer files.
When it happens
Trigger: Calling Post::observe('App\Observers\AuditObserver') when that class is not autoloadable: wrong namespace, typo, file not yet created, or composer autoload cache stale.
Common situations: Observer created in a non PSR-4 path; renamed namespace but boot reference not updated; package observers referenced without installing the package; stale composer dump-autoload after a move.
Related errors
- Call to undefined cast [{$castType}] on column [{$column}] i
- Could not verify the hashed value's configuration.
- Global scope must be an instance of Closure or Scope or be a
- No morph map defined for model [{$class}].
- This cache store does not support locks.
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/b75ceef18527e0b8.json.
Report an issue: GitHub.