Debugging the dreaded "Class log does not exist" error in Laravel

Every now and then I come accross a Class log does not exist exception in Laravel. This particular exception is thrown when something goes wrong really early in the application, before the exception handler is instantiated.

Whenever I come across this issue I'm stumped. Mostly it's related to an invalid configuration issue or an early service provider that throws an exception. I always forget how to debug this, so it's time to document my solution for tracking down the underlying error.

We can't see what's actually going wrong, because Laravel throws a second exception while trying to log and display the initial error. We end up with Class log does not exist because Laravel wants to log the exception before the logger class exists.

To find the original exception, we need to trace down the method that catches it. This happens in the handle method in the current Kernel class. That's Illuminate\Foundation\Http\Kernel if we're accessing our app via HTTP, or Illuminate\Foundation\Console\Kernel when using Artisan.

Let's go throught the console kernel's handle method.

<?php
 
/**
* Run the console application.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return int
*/
public function handle($input, $output = null)
{
try {
$this->bootstrap();
 
return $this->getArtisan()->run($input, $output);
} catch (Exception $e) {
$this->reportException($e);
 
$this->renderException($output, $e);
 
return 1;
} catch (Throwable $e) {
$e = new FatalThrowableError($e);
 
$this->reportException($e);
 
$this->renderException($output, $e);
 
return 1;
}
}

The exception will end up in one of the two catch blocks. By adding a quick dump after them, we can quickly inspect the real exception.

<?php
 
try {
$this->bootstrap();
 
return $this->getArtisan()->run($input, $output);
} catch (Exception $e) {
die("{$e->getMessage()} {$e->getTraceAsString()}");
 
$this->reportException($e);
 
$this->renderException($output, $e);
 
return 1;
} catch (Throwable $e) {
die("{$e->getMessage()} {$e->getTraceAsString()}");
 
$e = new FatalThrowableError($e);
 
$this->reportException($e);
 
$this->renderException($output, $e);
 
return 1;
}

That's all! Now we'll be able to see a meaningful message in our output instead of an irrelevant Class log does not exist trace.

Don't forget to remove the calls when your application's back up and running!