Skip to content

Laravel 12 Error Handling Guide: Common Mistakes and How to Fix Them

Learn Laravel 12 error handling best practices vs bad practices with real examples. Improve debugging, logging, and exception handling in Laravel apps.

Dasun Kalupahana 4 min read 2.7K views 0 comments

Introduction

Error handling is one of the most critical parts of building reliable web applications. In Laravel 12, error handling has been redefined with a cleaner and more centralized approach using the bootstrap/app.php file, replacing the old Handler.php system.

Whether you’re building an API or a web application, proper error handling ensures that your app behaves predictably, keeps users informed, and protects sensitive information. Unfortunately, many developers fall into bad habits like using dd() in production, returning generic error messages, or ignoring logging altogether.

In this guide, we’ll explore Laravel 12 error handling best practices, highlight common bad practices to avoid, and share practical examples of good implementations. By the end, you’ll know how to build more secure, professional, and user-friendly Laravel applications.


Why Do We Use Error Handling

Error handling is not just about fixing bugs — it’s about building resilient applications that handle unexpected scenarios gracefully. Here’s why it’s essential in Laravel 12 development:

  1. Improves User Experience (UX): Instead of showing raw errors or stack traces, you can display user-friendly messages.
  2. Increases Security: Prevents sensitive information (like SQL queries or server details) from being exposed to attackers.
  3. Helps Debugging: With proper logging and reporting, developers can quickly identify and fix issues.
  4. Ensures API Reliability: APIs can return structured JSON error responses, making them predictable for clients.
  5. Boosts Maintainability: Centralized error handling keeps your codebase clean and easier to manage.

In short, error handling in Laravel 12 ensures that your application is secure, stable, and user-friendly in both development and production environments.


🚫 Bad Practices in Error Handling

1.  Using dd() or dump() in Production

public function store(Request $request)
{
    dd($request->all()); // Debugging in live app
}

Exposes sensitive data (emails, passwords, tokens) and halts the application flow.

2. Leaving APP_DEBUG=true in Production

APP_ENV=production
APP_DEBUG=true

Shows stack traces, SQL queries, and server details to end-users.
A
huge security risk — hackers can exploit this information.

3. Ignoring Exception Handling

public function getUser($id)
{
    return User::findOrFail($id); // Crashes if user doesn’t exist
}

Unhandled exceptions break the app and return generic 500 errors instead of user-friendly messages.

4. Hardcoding Generic Error Messages

if (!$user) {
    return response()->json(['error' => 'Something went wrong']);
}

Confuses users, offers no debugging insight, and makes maintenance harder.

5. Logging Everything as info or error

Log::info('Database connection failed');

Using the wrong log levels buries important issues.

  • info for minor events
  • warning for suspicious activity
  • error for failures
  • critical for severe system crashes

6. Mixing HTML Errors in APIs

// Returning HTML in an API response
abort(404, 'Page not found');

APIs should return structured JSON, not Blade views or plain text.
Otherwise, clients (mobile apps, third-party systems) cannot parse responses.

7. Not Creating Custom Exceptions

throw new \Exception('Payment failed');

Using generic exceptions everywhere makes debugging difficult.
Instead, create domain-specific exceptions like InvalidPaymentException or OrderNotFoundException.

8. Swallowing Errors Without Logging

try {
    $user = User::findOrFail($id);
} catch (\Exception $e) {
    // Fail silently
}

If you don’t log errors, developers have no way to know what went wrong in production.

 

Error Handling Best Practices

1. Centralize Exception Handling in bootstrap/app.php

Instead of scattering error handling everywhere, keep it centralized.

<?php
  
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        //
    })
    ->withExceptions(function (Exceptions $exceptions) {
            
        $exceptions->renderable(function (NotFoundHttpException $e) {
            return response()->json([
                'message' => 'Record not found.'
            ], 404);
        });
             
    })->create();

Keeps all exception handling consistent.

2. Use Meaningful HTTP Status Codes

Always return the correct status code instead of generic 200 responses.

return response()->json([
    'success' => false,
    'error' => 'Unauthorized'
], 401);

Helps APIs communicate errors properly.

3. Leverage Built-in Validation

Prevent errors early by validating inputs before processing.

$request->validate([
    'email' => 'required|email',
    'password' => 'required|min:8',
]);

Stops invalid data from reaching business logic.

4. Use Try-Catch for Critical Operations

Wrap risky operations in try-catch to handle gracefully.

try {
    $user = User::findOrFail($id);
} catch (ModelNotFoundException $e) {
    return response()->json(['error' => 'User not found'], 404);
}

Prevents application crashes.

5. Log Exceptions with Proper Levels

Don’t log everything as info or error — use levels wisely.

Log::warning('User not found', ['id' => $id]);
Log::error('Database failure', ['exception' => $e]);

Makes debugging easier in production.

6. Report Exceptions in bootstrap/app.php

You can customize reporting separately from rendering.

$exceptions->report(function (Throwable $e) {
    Log::critical('System crash detected', [
        'message' => $e->getMessage(),
    ]);
});

Ensures important errors are logged before being displayed.

7. Hide Sensitive Information

Never show stack traces or debug data in production.

APP_ENV=production
APP_DEBUG=false

Protects your app from exposing security vulnerabilities.

8. Customize User-Friendly Error Pages

Provide meaningful error views for users.

{{-- resources/views/errors/404.blade.php --}}
<h1>404 - Page Not Found</h1>
<p>Oops! The page you are looking for doesn’t exist.</p>
<a href="{{ url('/') }}">Go Home</a>

Improves UX while keeping security intact.

9. Return JSON Errors for APIs

APIs should always respond with JSON, not HTML.

$exceptions->render(function (ModelNotFoundException $e, $request) {
    if ($request->expectsJson()) {
        return response()->json(['error' => 'Record not found'], 404);
    }
});

Keeps consistency for API consumers.

10. Use Custom Exceptions for Specific Errors

Instead of using generic errors, create domain-specific exceptions.

// app/Exceptions/InvalidPaymentException.php
class InvalidPaymentException extends \Exception {}

// usage
throw new InvalidPaymentException('Payment method not supported');

Handle it in bootstrap/app.php:

$exceptions->render(function (InvalidPaymentException $e) {
    return response()->json(['error' => $e->getMessage()], 400);
});

Makes debugging and maintenance much easier.

 

Conclusion

Error handling in Laravel 12 has evolved to be more streamlined and developer-friendly. By moving exception handling into the bootstrap/app.php file, Laravel makes it easier to centralize and customize error responses.

Following best practices — such as using proper HTTP status codes, leveraging validation, creating custom exceptions, logging errors correctly, and hiding sensitive details — ensures that your application is both secure and professional.

Ignoring error handling may work in development, but in production, it leads to frustrated users, security risks, and harder debugging. On the other hand, proper error handling builds trust, stability, and scalability into your Laravel projects.

👉 By adopting these Laravel 12 error handling best practices, you’ll not only reduce headaches for your development team but also deliver a better experience for your end users.


If you found this helpful, feel free to share or drop a comment. Happy coding with Laravel! 🧱✨

Free resources for this topic

Code snippets and fixes for this topic

Get one practical tip every week

New tutorials, fixes and free cheat sheets from DEV Talk, straight to your inbox. No spam, unsubscribe in one click.

Free download: Laravel interview questions (PDF)

Have a question about this post?

Ask the community: other developers and the author can answer.

Ask the community

Get notified about new articles

One click, no email needed. Turn it off anytime with the bell at the top.

Get new articles on your iPhone

Add DEV Talk to your Home Screen, open it, then tap the bell.

Rate this post
0.0
Share

Enjoying the content?

If this article helped you, you can support the author with a coffee. It keeps new posts coming.

Buy me a coffee (opens in a new tab)

Comments 0

Be kind. Comments with links are reviewed before they appear.

No comments yet

Be the first to share your thoughts.

Get new articles in your inbox

Practical tutorials and deep dives, about once a week. No spam, unsubscribe anytime.

Privacy policy

Add DEV Talk to your Home Screen

  1. 1 Tap the Share button in Safari's toolbar.
  2. 2 Scroll down and tap Add to Home Screen.
  3. 3 Tap Add. Open it from the Home Screen to read like an app and to turn on notifications with the bell.

We use cookies to improve your experience and analyze traffic. By continuing, you agree to our Privacy Policy.