Back to Blog

Fixing 404 Error in Laravel Model Route Binding with Middleware Priority

πŸ“Œ Introduction Laravel provides a robust model route binding feature, making it easy to fetch models from route parameters. However, in a multi-tenant application, you might encounter a 404 error when using model binding due to middleware execution order. Recently, I faced this issue while working with Laravel 11 and discovered the importance of middleware […]

Fixing 404 Error in Laravel Model Route Binding with Middleware Priority

πŸ“Œ Introduction

Laravel provides a robust model route binding feature, making it easy to fetch models from route parameters. However, in a multi-tenant application, you might encounter a 404 error when using model binding due to middleware execution order.

Recently, I faced this issue while working with Laravel 11 and discovered the importance of middleware priority. Here’s how I solved it.

πŸ” The Problem

In my multi-tenant Laravel application, I use a single database connection and determine the tenant ID dynamically via middleware. The middleware sets the tenant ID in config() from the session before queries execute.

However, when I used model route binding, I got a 404 error because:

  1. Laravel’s SubstituteBindings::class middleware was executing before my custom middleware.
  2. As a result, Laravel was trying to fetch the model before the tenant ID was set.
  3. The query lacked the tenant_id condition, returning no results and triggering a 404 page.

βœ… The Solution: Adjust Middleware Execution Order

Laravel 11 introduces the prependToPriorityList() method, allowing us to prioritize middleware execution order.

Step 1: Create a Middleware to Set Tenant ID

First, create a middleware that sets the tenant ID from the session into config().

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Session;

class SetTenant
{
    public function handle($request, Closure $next)
    {
        $tenantId = Session::get('tenant_id');
        Config::set('app.tenant_id', $tenantId);
        return $next($request);
    }
}

Step 2: Adjust Middleware Priority in AppServiceProvider

To ensure SetTenant runs before SubstituteBindings::class, use:

use App\Http\Middleware\SetTenant;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        //
        $middleware->prependToPriorityList(
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            SetTenant::class
        );
        $middleware->alias([
            'set_tenant' => SetTenant::class,
        ]);

    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

How This Works:

βœ… SetTenant::class runs first, setting the tenant ID.
βœ… SubstituteBindings::class runs after, ensuring model binding includes the tenant condition.

πŸ“– Laravel Documentation & Resources

  • πŸ“Œ Laravel 11 Middleware Priority: Read here
  • πŸ“Œ Laravel 10 Middleware Priority: Read here
  • πŸ“Œ GitHub Issue (Middleware Binding Order): Check here

🎯 Conclusion

Using prependToPriorityList() ensures that our middleware runs before Laravel binds models, fixing 404 errors in multi-tenant applications.

This small yet powerful adjustment can save you hours of debugging! Hope this helps fellow Laravel developers. πŸš€

Thanks for the reading! πŸ™‚