Fix PHP Fatal Error: Class 'ClassName' Not Found โ€” Autoload & Namespace Issues

intermediate๐Ÿ˜ PHP2026-04-21| PHP 7.x / 8.x, Composer, Laravel / Symfony / vanilla PHP, Linux/macOS/Windows

Error Message

Fatal error: Uncaught Error: Class 'ClassName' not found
#php#class#autoload#namespace

The error hits you out of nowhere

Your app was running fine. You pulled the latest code, ran a quick deploy, and now every page throws:

Fatal error: Uncaught Error: Class 'App\Services\PaymentService' not found in /var/www/html/src/Controllers/CheckoutController.php:42
Stack trace:
#0 {main}
  thrown in /var/www/html/src/Controllers/CheckoutController.php on line 42

Or maybe it's a third-party class like Stripe\Charge or Carbon\Carbon. Either way, PHP can't locate the class and execution stops cold.

Six root causes cover 99% of these failures. Work through them in this order โ€” each step eliminates the next most likely culprit.

Step 1: Check if the file physically exists

Before blaming autoload, confirm the class file is actually on disk:

# Replace with the actual class path
find /var/www/html -name "PaymentService.php" -type f

No output means the file is gone. It might never have been committed, got deleted, or lives on a branch that wasn't merged. Git can tell you:

git log --all --full-history -- src/Services/PaymentService.php

File exists but PHP still can't find it? Move to Step 2.

Step 2: Verify the namespace matches the directory structure

Namespace mismatches cause this error more than anything else. PHP's PSR-4 autoloader maps namespaces to directories โ€” if they don't align exactly, the class is invisible to PHP even when the file is sitting right there.

Open the class file and check the declared namespace:

<?php
// src/Services/PaymentService.php
namespace App\Services;   // โ† must match the directory path

class PaymentService
{
    // ...
}

Then check composer.json to see how PSR-4 is wired:

{
  "autoload": {
    "psr-4": {
      "App\\": "src/"    // โ† App\ maps to src/
    }
  }
}

With this config, App\Services\PaymentService must live at src/Services/PaymentService.php. Three mismatches show up constantly:

  • File is at src/services/PaymentService.php (lowercase s) โ€” Linux filesystems are case-sensitive, Windows isn't, so it works on your laptop and explodes on the server
  • Namespace says App\Service (singular) but the directory is Services (plural)
  • Extra folder levels in the path that aren't reflected in the namespace

Fix the namespace or move the file to match, then regenerate the autoloader.

Step 3: Regenerate the Composer autoloader

Composer builds a classmap at install time and caches it. Add new files or rename namespaces without regenerating, and PHP has no idea those classes exist.

# Standard regeneration
composer dump-autoload

# Optimized for production (classmap of every class)
composer dump-autoload --optimize

# Not sure what's registered? Check the generated file
cat vendor/composer/autoload_psr4.php

Run dump-autoload, reload the page. Error gone? Stale autoload cache was the culprit โ€” takes 3 seconds to fix and wastes hours when you don't think of it.

Step 4: Check the use statement in the consuming class

A correct file and a valid namespace still won't save you if the use statement has a typo:

<?php
namespace App\Controllers;

// Wrong โ€” singular instead of plural
use App\Service\PaymentService;

// Right
use App\Services\PaymentService;

class CheckoutController
{
    public function checkout()
    {
        $payment = new PaymentService();  // Class 'App\Service\PaymentService' not found
    }
}

Also watch for a missing use statement entirely. Without an import, PHP looks for the class in the current namespace and fails:

<?php
namespace App\Controllers;

// Missing: use Carbon\Carbon;

class ReportController
{
    public function generate()
    {
        $date = new Carbon();  // Fatal error: Class 'App\Controllers\Carbon' not found
    }
}

Step 5: For non-Composer projects, check manual require paths

Legacy codebase, custom framework, no Composer? The class file must be explicitly required before anything touches it:

<?php
// Before using MyClass anywhere
require_once __DIR__ . '/../lib/MyClass.php';

$obj = new MyClass();

Or wire a manual autoloader so you're not writing require_once everywhere:

<?php
spl_autoload_register(function ($className) {
    $file = __DIR__ . '/lib/' . str_replace('\\', '/', $className) . '.php';
    if (file_exists($file)) {
        require_once $file;
    }
});

Step 6: Vendor package class missing after install

When the missing class belongs to a package โ€” Stripe, Guzzle, Monolog โ€” the problem is usually that the package was never installed, or the vendor/ directory didn't make it to the server:

# Check if the package is actually listed
composer show | grep stripe

# Not there? Install it
composer require stripe/stripe-php

# vendor/ looks incomplete (partial FTP upload, partial deploy)
composer install --no-dev

FTP deployments are notorious for this. Someone uploads the app files, forgets vendor/, and wonders why production is broken. Always deploy the entire vendor/ directory, or run composer install directly on the server.

Verify the fix

Don't go straight to the browser. Test from the CLI first โ€” it gives you a clean error without any web framework noise:

# Try to instantiate the class directly
php -r "require 'vendor/autoload.php'; new App\\Services\\PaymentService();"

# Or use reflection to check if PHP can load it
php -r "
require 'vendor/autoload.php';
if (class_exists('App\\Services\\PaymentService')) {
    echo 'Class found OK' . PHP_EOL;
} else {
    echo 'Still not found' . PHP_EOL;
}
"

You want Class found OK. Anything else means the namespace or file path is still off.

Quick-reference checklist

  • File physically exists at the expected path: find or ls
  • Namespace in the file matches the PSR-4 mapping in composer.json
  • Directory and file name casing match the namespace exactly (watch out on Linux)
  • use statement in the calling file is correct and present
  • Ran composer dump-autoload after any file or namespace change
  • vendor/ directory is complete and up to date on the server

The pattern behind the 2 AM pages

Almost every midnight incident traces back to one of three things. A deploy that didn't include vendor/. A case sensitivity mismatch that only surfaces on Linux. Or a namespace rename where someone forgot to run dump-autoload.

The fix for all three: add composer dump-autoload --optimize to your deploy script. One line, and you eliminate an entire category of these incidents permanently.

Related Error Notes